/*
  ==============================================================================

   This file is part of the JUCE framework.
   Copyright (c) Raw Material Software Limited

   JUCE is an open source framework subject to commercial or open source
   licensing.

   By downloading, installing, or using the JUCE framework, or combining the
   JUCE framework with any other source code, object code, content or any other
   copyrightable work, you agree to the terms of the JUCE End User Licence
   Agreement, and all incorporated terms including the JUCE Privacy Policy and
   the JUCE Website Terms of Service, as applicable, which will bind you. If you
   do not agree to the terms of these agreements, we will not license the JUCE
   framework to you, and you must discontinue the installation or download
   process and cease use of the JUCE framework.

   JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
   JUCE Privacy Policy: https://juce.com/juce-privacy-policy
   JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/

   Or:

   You may also use this code under the terms of the AGPLv3:
   https://www.gnu.org/licenses/agpl-3.0.en.html

   THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
   WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.

  ==============================================================================
*/

namespace juce
{

// This byte-code is generated from native/java/com/rmsl/juce/ComponentPeerView.java with min sdk version 16
// See juce_core/native/java/README.txt on how to generate this byte-code.
const uint8 javaComponentPeerView[]
{
  0x1f, 0x8b, 0x08, 0x08, 0xbc, 0xe2, 0x6c, 0x68, 0x00, 0x03, 0x63, 0x6c,
  0x61, 0x73, 0x73, 0x65, 0x73, 0x2e, 0x64, 0x65, 0x78, 0x00, 0xa5, 0x7c,
  0x0b, 0x7c, 0xdc, 0x45, 0xb5, 0xff, 0x99, 0xdf, 0xbe, 0x92, 0xcd, 0x26,
  0xd9, 0xdd, 0x34, 0x4d, 0xfa, 0xde, 0x86, 0xb4, 0xa4, 0xd0, 0x4d, 0x36,
  0x69, 0xd3, 0x26, 0x4d, 0x1f, 0x69, 0xd3, 0xa4, 0x4d, 0x9a, 0xb6, 0x69,
  0xb3, 0x0d, 0x6d, 0x52, 0x68, 0x37, 0xc9, 0xb6, 0x59, 0xba, 0xd9, 0xdd,
  0xec, 0x6e, 0xd2, 0x96, 0xd7, 0x2d, 0x50, 0x6d, 0xa9, 0xa0, 0x55, 0x41,
  0x1e, 0x56, 0x41, 0xde, 0x60, 0x51, 0xbc, 0x56, 0xe5, 0x82, 0x0f, 0x50,
  0x50, 0x54, 0xae, 0xa2, 0x82, 0x82, 0x22, 0x70, 0x05, 0xbd, 0xa8, 0xc8,
  0x43, 0xf1, 0xc2, 0xf5, 0xc5, 0xff, 0x7b, 0x66, 0x66, 0x37, 0xbf, 0x6d,
  0x1a, 0xd0, 0xff, 0x4d, 0x3e, 0xdf, 0xdf, 0x39, 0x73, 0xce, 0x99, 0xf7,
  0x99, 0x33, 0x33, 0xbf, 0xdd, 0x64, 0x30, 0x7c, 0xc0, 0x19, 0x58, 0xb4,
  0x94, 0x12, 0x53, 0x7f, 0xfb, 0x97, 0x44, 0xf7, 0xd6, 0xcf, 0x74, 0x7d,
  0x2b, 0x78, 0xdf, 0x47, 0x2e, 0xbd, 0xf7, 0x73, 0x2b, 0x1e, 0x3b, 0xe6,
  0xdd, 0xba, 0x74, 0x59, 0xca, 0xdd, 0x4d, 0x94, 0x20, 0xa2, 0x03, 0x3d,
  0x8b, 0xbd, 0xa4, 0x7f, 0x3a, 0xb7, 0x12, 0x5d, 0x26, 0x94, 0x7c, 0x1d,
  0x30, 0x64, 0x27, 0x8a, 0x83, 0x1e, 0x76, 0x10, 0x55, 0x80, 0x3e, 0xe0,
  0x22, 0xfa, 0x2d, 0xe8, 0xe3, 0x85, 0x44, 0x05, 0xa0, 0xee, 0x52, 0xa2,
  0x5b, 0x96, 0xc3, 0x7e, 0x2a, 0xd1, 0x57, 0x6b, 0x89, 0xbe, 0x0e, 0x3c,
  0x02, 0x3c, 0x0a, 0x7c, 0x07, 0x78, 0x1d, 0x28, 0xab, 0x23, 0x5a, 0x05,
  0xac, 0x01, 0xda, 0x80, 0x76, 0x60, 0x0b, 0xb0, 0x0d, 0xe8, 0x03, 0x06,
  0x80, 0x24, 0x70, 0x0c, 0xf8, 0x04, 0x70, 0x2f, 0x70, 0x1f, 0xf0, 0x05,
  0xe0, 0x14, 0xf0, 0x00, 0xf0, 0x55, 0xe0, 0x11, 0xe0, 0x31, 0xe0, 0x7b,
  0xc0, 0x0f, 0x80, 0x1f, 0x01, 0x4f, 0x03, 0xcf, 0x02, 0xef, 0x00, 0x9e,
  0x45, 0x44, 0x53, 0x80, 0x72, 0x60, 0x16, 0x30, 0x17, 0x98, 0x0f, 0x2c,
  0x04, 0x02, 0x40, 0x3d, 0xb0, 0x0c, 0x68, 0x06, 0xb6, 0x03, 0x1f, 0x06,
  0xee, 0x01, 0x1e, 0x05, 0x5e, 0x00, 0xde, 0x05, 0xe6, 0x2c, 0x26, 0xea,
  0x00, 0x06, 0x81, 0xcb, 0x80, 0xeb, 0x81, 0x2f, 0x02, 0x8f, 0x03, 0xcf,
  0x03, 0x6f, 0x03, 0x9e, 0x7a, 0x22, 0x3f, 0xb0, 0x0e, 0x88, 0x01, 0xc7,
  0x80, 0x9b, 0x81, 0x53, 0xc0, 0x8b, 0xc0, 0x3f, 0x80, 0xb2, 0x25, 0x44,
  0x8b, 0x80, 0x0b, 0x80, 0x14, 0x70, 0x0d, 0xf0, 0x18, 0xf0, 0x1b, 0xe0,
  0xef, 0xc0, 0x9c, 0xa5, 0x18, 0x0b, 0xe0, 0x20, 0x70, 0x1f, 0xf0, 0x6b,
  0xa0, 0xb4, 0x81, 0x68, 0x39, 0x30, 0x04, 0x5c, 0x0f, 0x3c, 0x05, 0x78,
  0x1a, 0x89, 0x36, 0x01, 0xff, 0x06, 0xdc, 0x07, 0xbc, 0x06, 0x2c, 0x59,
  0x46, 0x34, 0x02, 0x7c, 0x06, 0x78, 0x0a, 0x78, 0x1b, 0x98, 0xd1, 0x44,
  0xd4, 0x04, 0x5c, 0x00, 0x1c, 0x06, 0x6e, 0x03, 0xbe, 0x06, 0x3c, 0x0f,
  0xfc, 0x09, 0x70, 0x60, 0x8e, 0x66, 0x00, 0x75, 0xc0, 0x7a, 0xa0, 0x17,
  0x88, 0x02, 0x17, 0x01, 0x57, 0x02, 0xd7, 0x02, 0xb7, 0x02, 0x77, 0x00,
  0xf7, 0x00, 0x9f, 0x03, 0x4e, 0x01, 0x0f, 0x01, 0x0f, 0x03, 0x8f, 0x02,
  0x4f, 0x00, 0x3f, 0x06, 0x9e, 0x05, 0x9e, 0x07, 0x5e, 0x02, 0x7e, 0x0b,
  0xbc, 0x06, 0xfc, 0x11, 0x78, 0x1b, 0xf8, 0x3b, 0x60, 0x5d, 0x41, 0x94,
  0x0f, 0x14, 0x01, 0xa5, 0xc0, 0x6c, 0xa0, 0x12, 0x58, 0x00, 0xd4, 0x00,
  0xf5, 0x40, 0x13, 0xb0, 0x0a, 0x58, 0x07, 0x74, 0x00, 0x9b, 0x81, 0x6d,
  0x40, 0x2f, 0x70, 0x01, 0x10, 0x06, 0xf6, 0x01, 0x71, 0x20, 0x0d, 0x5c,
  0x02, 0x5c, 0x09, 0x1c, 0x01, 0x3e, 0x04, 0x7c, 0x04, 0xf8, 0x24, 0x70,
  0x17, 0x70, 0x0a, 0x78, 0x04, 0xf8, 0x01, 0xf0, 0x0b, 0xe0, 0x15, 0xe0,
  0xcf, 0x80, 0xb1, 0x92, 0xa8, 0x18, 0x98, 0x09, 0x2c, 0x00, 0xea, 0x81,
  0x35, 0xc0, 0x26, 0xa0, 0x17, 0xd8, 0x03, 0x24, 0x81, 0xcb, 0x80, 0x63,
  0xc0, 0x27, 0x80, 0xdb, 0x80, 0x7f, 0x07, 0x1e, 0x07, 0x9e, 0x06, 0x7e,
  0x0e, 0xfc, 0x19, 0x70, 0xac, 0x22, 0x9a, 0x0e, 0xf8, 0x81, 0x7a, 0x60,
  0x05, 0xb0, 0x19, 0xb8, 0x00, 0x08, 0x03, 0x63, 0xc0, 0x47, 0x80, 0x13,
  0xc0, 0x49, 0xe0, 0x21, 0xe0, 0x47, 0xc0, 0x6b, 0xc0, 0xdb, 0x80, 0x68,
  0xc6, 0x7a, 0x01, 0xfc, 0x40, 0x03, 0xd0, 0x06, 0x0c, 0x00, 0x97, 0x03,
  0x57, 0x03, 0x27, 0x80, 0xfb, 0x80, 0x47, 0x81, 0x9f, 0x02, 0xaf, 0x02,
  0x7f, 0x05, 0xdc, 0xab, 0x89, 0xce, 0x06, 0x16, 0x01, 0xab, 0x81, 0x4d,
  0xc0, 0x4e, 0x60, 0x3f, 0x70, 0x23, 0x70, 0x3b, 0xf0, 0x0d, 0xe0, 0x19,
  0xe0, 0x0f, 0x80, 0x75, 0x0d, 0xfc, 0x1d, 0x68, 0x04, 0x3a, 0x80, 0x5d,
  0xc0, 0x30, 0x70, 0x09, 0x70, 0x0d, 0xf0, 0x49, 0xe0, 0x76, 0xe0, 0x3e,
  0xe0, 0x41, 0xe0, 0xfb, 0xc0, 0xf3, 0xc0, 0x1b, 0x80, 0xa3, 0x05, 0x7e,
  0x0b, 0x2c, 0x00, 0x56, 0x02, 0x9b, 0x80, 0x01, 0x20, 0x09, 0x5c, 0x03,
  0x7c, 0x0a, 0x78, 0x08, 0x78, 0x04, 0xf8, 0x0e, 0xf0, 0x43, 0xe0, 0xb7,
  0xc0, 0x5f, 0x00, 0xd7, 0x5a, 0xcc, 0x33, 0xe0, 0x07, 0x96, 0x03, 0xed,
  0xc0, 0x2e, 0x20, 0x01, 0x5c, 0x0e, 0x1c, 0x07, 0xee, 0x01, 0xbe, 0x0c,
  0x7c, 0x1f, 0x78, 0x05, 0x78, 0x13, 0x78, 0x1b, 0xb0, 0xb5, 0x22, 0x2f,
  0x50, 0x05, 0x54, 0x03, 0xcb, 0x80, 0x0d, 0x40, 0x2f, 0xb0, 0x0f, 0x18,
  0x03, 0x0e, 0x03, 0xd7, 0x03, 0x9f, 0x01, 0x3e, 0x0b, 0x7c, 0x1d, 0x78,
  0x16, 0x78, 0x19, 0x78, 0x0d, 0x70, 0xb4, 0x11, 0x4d, 0x05, 0x66, 0x01,
  0xf3, 0x80, 0x73, 0x81, 0x3a, 0xa0, 0x01, 0x68, 0x03, 0x36, 0x01, 0xfd,
  0xc0, 0x28, 0x70, 0x0c, 0x38, 0x01, 0x7c, 0x1e, 0x78, 0x02, 0x78, 0x01,
  0xf8, 0x23, 0x50, 0x80, 0x80, 0x57, 0x02, 0x54, 0x00, 0x75, 0x40, 0x33,
  0xb0, 0x01, 0xe8, 0x05, 0x06, 0x80, 0x61, 0xe0, 0x12, 0xe0, 0x2a, 0xe0,
  0x06, 0xe0, 0x2e, 0xe0, 0xcb, 0xc0, 0xa3, 0xc0, 0x13, 0xc0, 0x4f, 0x80,
  0x5f, 0x01, 0x62, 0x3d, 0xe2, 0x10, 0x30, 0x0b, 0x58, 0x0d, 0xec, 0x02,
  0xf6, 0x01, 0x07, 0x81, 0xcb, 0x80, 0x0f, 0x03, 0x27, 0x80, 0x2f, 0x01,
  0xdf, 0x07, 0x5e, 0x04, 0x5e, 0x03, 0x6c, 0xed, 0x88, 0x0b, 0x80, 0x1f,
  0x58, 0x02, 0x6c, 0x06, 0xf6, 0x00, 0x97, 0x02, 0x37, 0x01, 0x5f, 0x04,
  0x1e, 0x06, 0x7e, 0x08, 0xfc, 0x02, 0xf8, 0x3d, 0xf0, 0x26, 0xf0, 0x2e,
  0x50, 0xd4, 0x81, 0x31, 0x04, 0xfc, 0xc0, 0x32, 0xa0, 0x15, 0xd8, 0x02,
  0xec, 0x00, 0x2e, 0x02, 0x6e, 0x06, 0xbe, 0x0b, 0xbc, 0x09, 0x78, 0x36,
  0x20, 0x1e, 0x02, 0x5b, 0x80, 0x14, 0x70, 0x1d, 0xf0, 0x20, 0xf0, 0x2b,
  0xe0, 0x77, 0xc0, 0x1f, 0x81, 0xbf, 0x01, 0xa2, 0x13, 0xeb, 0x16, 0xd8,
  0x0c, 0xc4, 0x81, 0x8f, 0x01, 0x37, 0x02, 0xb7, 0x02, 0x77, 0x03, 0xff,
  0x01, 0x7c, 0x1f, 0xe0, 0xcd, 0x63, 0x0a, 0x30, 0x03, 0x38, 0x07, 0x38,
  0x17, 0x58, 0x08, 0xf8, 0x81, 0x6a, 0xa0, 0x06, 0x08, 0x00, 0xd8, 0x0a,
  0x08, 0x61, 0x9a, 0x10, 0x66, 0x09, 0x61, 0x94, 0x10, 0x26, 0x09, 0xa1,
  0x90, 0x10, 0xfa, 0x08, 0xa1, 0x8e, 0x10, 0xda, 0x08, 0xa1, 0x8c, 0x10,
  0xae, 0x08, 0x61, 0x84, 0xb0, 0x84, 0x09, 0x4b, 0x8f, 0xb0, 0x0c, 0x08,
  0xae, 0x4d, 0x70, 0x51, 0x82, 0xab, 0x11, 0x5c, 0x86, 0x30, 0xe5, 0xd4,
  0xa6, 0xf7, 0x28, 0x0c, 0x1d, 0x61, 0x08, 0x08, 0x5d, 0xa3, 0x0d, 0xbc,
  0x87, 0x01, 0x1b, 0x81, 0x4d, 0xc0, 0x66, 0xa0, 0x0b, 0xd8, 0x02, 0x60,
  0x6b, 0x23, 0x6c, 0x79, 0x14, 0x04, 0xb6, 0x01, 0x3d, 0xc0, 0x79, 0xc0,
  0x76, 0x60, 0x07, 0xd0, 0x0b, 0xf4, 0x01, 0x3b, 0x81, 0xf3, 0x81, 0x0b,
  0x80, 0x5d, 0xc0, 0x6e, 0x20, 0x04, 0xf4, 0x03, 0x03, 0xc0, 0x20, 0x10,
  0x06, 0xf6, 0x00, 0x7b, 0x79, 0x8f, 0x04, 0x22, 0xc0, 0x85, 0xa4, 0xf6,
  0xcd, 0x6b, 0x80, 0x1b, 0x81, 0x9b, 0x48, 0x8d, 0x4d, 0xe6, 0xa7, 0x44,
  0xd3, 0x40, 0x8d, 0x1a, 0x2f, 0xa1, 0xd3, 0x53, 0x35, 0xcf, 0xf2, 0x32,
  0xcd, 0x37, 0x80, 0x2f, 0xd7, 0x7c, 0x33, 0xf8, 0x69, 0x9a, 0x5f, 0x0f,
  0x7e, 0xba, 0xe6, 0xbb, 0x4c, 0xfc, 0x76, 0x13, 0xbf, 0xbb, 0x46, 0xcd,
  0x85, 0xa1, 0xcb, 0x9f, 0xa9, 0x79, 0x2e, 0x67, 0x96, 0xe6, 0x87, 0xc0,
  0xfb, 0x40, 0xed, 0xda, 0x66, 0x3e, 0x90, 0xc7, 0xed, 0xd7, 0x72, 0xb7,
  0x96, 0x33, 0xef, 0x31, 0xf1, 0xd3, 0x4c, 0xfc, 0x2c, 0xcd, 0x57, 0x6a,
  0xfe, 0x00, 0xf2, 0x2e, 0xd0, 0xfc, 0x21, 0x5d, 0x8e, 0xcf, 0x64, 0x7f,
  0x96, 0x89, 0x9f, 0xa7, 0xf9, 0xb9, 0x9a, 0xe7, 0xbe, 0x9f, 0xad, 0xf9,
  0xab, 0x75, 0xde, 0xf9, 0xa6, 0xb6, 0x71, 0xb9, 0xd7, 0x6a, 0xf9, 0x39,
  0x5a, 0xce, 0xe5, 0x2d, 0xd6, 0xfd, 0x62, 0x1b, 0xf6, 0xa7, 0x13, 0x35,
  0xea, 0x9c, 0xd2, 0xa4, 0xc7, 0x90, 0xcb, 0x5f, 0xa1, 0xcb, 0x3f, 0x4b,
  0xf3, 0x6c, 0x5f, 0xa5, 0xf9, 0xdb, 0x75, 0x99, 0x2b, 0x4d, 0x75, 0x31,
  0x7f, 0x52, 0xcb, 0x57, 0x69, 0x79, 0x85, 0xe6, 0xb9, 0xcc, 0x79, 0x9a,
  0x3f, 0xa5, 0x6d, 0x56, 0x9b, 0xf2, 0xb2, 0x8f, 0x3e, 0xac, 0xfb, 0xc2,
  0xfc, 0xe3, 0x35, 0xca, 0x27, 0x5a, 0xb4, 0xcd, 0x88, 0xe6, 0xb9, 0x3d,
  0x49, 0xcd, 0x73, 0x99, 0x29, 0xcd, 0x3f, 0x09, 0x3e, 0xad, 0xf9, 0xe7,
  0xc0, 0x8f, 0x6a, 0xfe, 0x15, 0xf0, 0x63, 0x9a, 0xe7, 0xf6, 0xef, 0xd7,
  0xfc, 0x1b, 0xe0, 0x0f, 0x68, 0x9e, 0xdb, 0x73, 0x30, 0x53, 0x17, 0x16,
  0xdc, 0x45, 0x9a, 0x77, 0x81, 0xbf, 0x44, 0xf3, 0x53, 0xc0, 0x5f, 0xac,
  0x79, 0x9f, 0x89, 0xaf, 0x02, 0x7f, 0x69, 0xa6, 0x6d, 0xe0, 0x2f, 0xcb,
  0xb4, 0x0d, 0xfc, 0x95, 0x99, 0x7a, 0x4d, 0xf2, 0xf5, 0x26, 0xbe, 0x0b,
  0xfc, 0x51, 0xcd, 0x6f, 0x37, 0xc9, 0x07, 0x4d, 0x7c, 0xd4, 0xc4, 0xa7,
  0x4d, 0x3c, 0x8f, 0x55, 0xa6, 0xfc, 0x4b, 0x20, 0x3f, 0xa4, 0xf9, 0xc3,
  0xe0, 0x0f, 0x6b, 0xfe, 0x38, 0xf8, 0x0f, 0x68, 0xfe, 0x84, 0x29, 0xef,
  0x49, 0x53, 0xdb, 0x4e, 0x99, 0xe4, 0x5f, 0x35, 0xf1, 0x8f, 0x82, 0xff,
  0x37, 0xcd, 0xb3, 0x5f, 0x1d, 0xd1, 0xfc, 0x13, 0x26, 0x9b, 0x99, 0x90,
  0x1f, 0xd3, 0xfc, 0x53, 0x26, 0x39, 0xfb, 0xd2, 0x15, 0x9a, 0x67, 0x3f,
  0xf9, 0xa0, 0xe6, 0x5f, 0x34, 0xd5, 0xfb, 0x2a, 0xf8, 0xab, 0x34, 0xff,
  0x96, 0x29, 0x2f, 0xaf, 0xc1, 0xcb, 0x33, 0x73, 0x51, 0x3b, 0x2e, 0x77,
  0xd5, 0x8e, 0xcb, 0xa7, 0xd4, 0x8e, 0x97, 0xe3, 0x33, 0xd9, 0xb0, 0xef,
  0x65, 0xf8, 0x2a, 0xc8, 0x3f, 0x94, 0x99, 0x17, 0xf0, 0x57, 0x67, 0xe6,
  0xc5, 0x64, 0xbf, 0xde, 0xc4, 0x77, 0xd5, 0xaa, 0xf8, 0xb3, 0x56, 0xfb,
  0xdb, 0x87, 0x35, 0xcf, 0x3e, 0xf6, 0x11, 0xcd, 0x6f, 0xaf, 0x1d, 0xe7,
  0x07, 0xc1, 0x1f, 0xd7, 0x7c, 0x02, 0xfc, 0x47, 0x35, 0xcf, 0x3e, 0xf6,
  0x31, 0xcd, 0x1f, 0x80, 0xfc, 0xe3, 0x9a, 0x3f, 0x0c, 0xfe, 0x3a, 0xcd,
  0x1f, 0x07, 0x7f, 0xad, 0xe6, 0x6f, 0x30, 0xc9, 0x79, 0x9c, 0x3f, 0xa1,
  0xf9, 0x5b, 0x20, 0xbf, 0x5e, 0xf3, 0xf7, 0x9b, 0xec, 0x5d, 0x26, 0x9e,
  0xfb, 0x7b, 0x83, 0xe6, 0xb9, 0x8f, 0x85, 0x88, 0x62, 0xff, 0x41, 0x8a,
  0xa6, 0x10, 0xd0, 0x8a, 0x40, 0x87, 0x79, 0x2c, 0xb0, 0xaa, 0xbf, 0xa8,
  0x69, 0xb1, 0x60, 0x2a, 0xc8, 0xa3, 0xa9, 0x57, 0xd3, 0x12, 0x4d, 0xa7,
  0x68, 0x5a, 0x2a, 0x94, 0xbd, 0x4f, 0xf0, 0x5e, 0xb4, 0x8a, 0xbe, 0x45,
  0x4c, 0x3d, 0xf4, 0x6d, 0x49, 0x17, 0xd3, 0xa0, 0x94, 0xd7, 0xd3, 0x45,
  0x82, 0xf7, 0x29, 0x0f, 0x3d, 0x48, 0x4c, 0xab, 0xe9, 0xab, 0x92, 0x2a,
  0x7d, 0x8d, 0xd6, 0x07, 0x40, 0x13, 0x9a, 0x72, 0xba, 0x16, 0x2d, 0x9e,
  0x23, 0x69, 0x1d, 0x8d, 0x08, 0xde, 0xdb, 0x94, 0xbe, 0x4e, 0xeb, 0xeb,
  0xa0, 0xb9, 0x44, 0x70, 0x8c, 0x32, 0xc8, 0x2d, 0x38, 0x3e, 0x55, 0xd2,
  0xbf, 0x13, 0xd3, 0x1a, 0x7a, 0x48, 0xd2, 0x8c, 0xbc, 0x8e, 0x66, 0x4b,
  0x1a, 0xa0, 0x79, 0x92, 0xae, 0xa5, 0x95, 0x92, 0x16, 0xd0, 0x2a, 0x50,
  0x1b, 0x76, 0xc3, 0xb5, 0x82, 0x63, 0x75, 0x21, 0x3d, 0x49, 0x4c, 0x2b,
  0xe9, 0x35, 0xd0, 0x7c, 0xec, 0xb4, 0x4e, 0x49, 0xcf, 0xa7, 0xf5, 0xd0,
  0x3b, 0xb1, 0x53, 0x72, 0xba, 0x40, 0xcb, 0x0b, 0x30, 0x72, 0xed, 0x82,
  0xc7, 0x51, 0xa5, 0x3d, 0xa8, 0x6f, 0xae, 0x60, 0xda, 0x43, 0x6d, 0x92,
  0x9e, 0x47, 0x5b, 0x05, 0xef, 0x51, 0xf9, 0xf4, 0x2a, 0x29, 0xfa, 0x07,
  0x49, 0xd7, 0xd2, 0x16, 0xc8, 0x4b, 0xb1, 0x53, 0x72, 0xbe, 0x32, 0xec,
  0x90, 0x4c, 0xa7, 0x21, 0xc7, 0xaf, 0x24, 0x5d, 0x47, 0x6b, 0x04, 0xef,
  0x37, 0x7e, 0x29, 0x9f, 0x8e, 0x72, 0xff, 0x53, 0xd2, 0x79, 0xf4, 0x13,
  0x9d, 0xfe, 0xb5, 0xa6, 0x7f, 0x22, 0xde, 0x8b, 0x94, 0x9e, 0xe9, 0x0f,
  0x34, 0xfd, 0xa1, 0xa4, 0x4e, 0x7a, 0x56, 0xa7, 0xff, 0x5b, 0x52, 0x0b,
  0xbd, 0x42, 0x6a, 0xef, 0xfa, 0xad, 0xa6, 0xbf, 0x93, 0x54, 0xd0, 0xff,
  0x6a, 0xfa, 0x17, 0xe2, 0xfd, 0xa5, 0x8c, 0x1e, 0x95, 0xd4, 0xa0, 0xe7,
  0x34, 0x7d, 0x5d, 0xd2, 0xd5, 0xf4, 0x8e, 0xa4, 0x0b, 0x69, 0x1b, 0xda,
  0x37, 0x1b, 0x11, 0x9e, 0xdb, 0x37, 0x1b, 0xbb, 0xf6, 0x62, 0x99, 0xee,
  0xa7, 0x7a, 0x49, 0x6b, 0xa8, 0x41, 0x70, 0xec, 0xde, 0x48, 0x5f, 0x22,
  0x45, 0x5b, 0x05, 0xef, 0x15, 0x5e, 0xfa, 0x19, 0x31, 0x5d, 0x48, 0x9b,
  0x05, 0xc7, 0x7c, 0x83, 0x06, 0x04, 0xef, 0x1b, 0x0b, 0xc9, 0x25, 0xa9,
  0x9f, 0xba, 0x75, 0x3a, 0xa8, 0xe9, 0x4e, 0xc1, 0xfb, 0xdf, 0x2e, 0x9a,
  0x21, 0x78, 0x5f, 0xd8, 0x20, 0xeb, 0x9b, 0x87, 0x11, 0x9a, 0x2f, 0xd3,
  0xe7, 0x52, 0x8b, 0xe0, 0x7d, 0x41, 0x8d, 0xff, 0xd9, 0x38, 0x99, 0x28,
  0x7a, 0x2e, 0x7d, 0x5d, 0xd2, 0x3c, 0x7a, 0x4a, 0xd3, 0xa7, 0x25, 0x75,
  0xd3, 0x33, 0xc4, 0xfb, 0xdb, 0x5e, 0x2a, 0x12, 0x4c, 0x3b, 0x68, 0x9d,
  0xa4, 0x11, 0xba, 0x40, 0xf0, 0xb9, 0x4a, 0x95, 0x73, 0x2e, 0xfc, 0xe5,
  0xaf, 0xc4, 0x67, 0x2c, 0x95, 0x5e, 0xa8, 0xd3, 0x7e, 0x9d, 0xf6, 0xeb,
  0x74, 0x35, 0x4e, 0x3d, 0x4e, 0x49, 0xd7, 0xd0, 0x97, 0x25, 0xdd, 0x46,
  0x0f, 0x48, 0xba, 0x80, 0xfe, 0x28, 0x69, 0x2b, 0x35, 0x4a, 0xff, 0x6f,
  0xa3, 0x65, 0x42, 0xa5, 0x9b, 0x84, 0xb2, 0x5b, 0x2e, 0x69, 0x0b, 0xa5,
  0x35, 0x1d, 0xd5, 0x74, 0x4c, 0xd3, 0xfd, 0x72, 0x5d, 0x74, 0xcb, 0xf2,
  0x6b, 0x74, 0x7f, 0x6a, 0x74, 0xfb, 0x6b, 0x28, 0x46, 0x1b, 0xe5, 0x3a,
  0xd9, 0x2a, 0xf5, 0x01, 0x9c, 0x64, 0x1e, 0x95, 0xf4, 0x1c, 0x7a, 0x5c,
  0xa7, 0xbf, 0x2b, 0x69, 0x88, 0x9a, 0xe5, 0xfa, 0xd9, 0x2c, 0xed, 0x6a,
  0xb9, 0x67, 0x72, 0xdd, 0xa8, 0x7c, 0x75, 0x90, 0x7f, 0x5a, 0xd3, 0x9b,
  0x25, 0x9d, 0x4d, 0xb7, 0x48, 0x7a, 0x2e, 0xed, 0x12, 0x8a, 0xee, 0x16,
  0x7c, 0x9e, 0x54, 0xfd, 0x5d, 0x8c, 0x12, 0x9c, 0xa4, 0xd6, 0xdb, 0x8f,
  0x24, 0x75, 0xd0, 0x8f, 0x75, 0xfa, 0x97, 0x9a, 0x3e, 0xaf, 0xe9, 0x4b,
  0x92, 0xce, 0xa7, 0x37, 0x74, 0xfa, 0x4d, 0x49, 0x77, 0x50, 0x99, 0x5c,
  0xaf, 0xbb, 0x68, 0xba, 0xa4, 0x7e, 0xea, 0x94, 0xb4, 0x97, 0xce, 0xd3,
  0xeb, 0xd4, 0x4a, 0x8a, 0xda, 0x34, 0xb5, 0x4b, 0xba, 0x52, 0xd6, 0x5b,
  0x8f, 0x93, 0xe1, 0x27, 0x25, 0xb5, 0xd1, 0x09, 0x49, 0x1b, 0xe8, 0x53,
  0x92, 0xba, 0xe8, 0x33, 0x92, 0x76, 0xd1, 0xad, 0x92, 0x4e, 0xa1, 0xdb,
  0x24, 0xdd, 0x47, 0xb7, 0x4b, 0x5a, 0x41, 0x77, 0x68, 0x7a, 0xa7, 0xce,
  0x7f, 0x97, 0xa4, 0x17, 0xd2, 0xdd, 0x92, 0x2e, 0xa2, 0x7b, 0x24, 0x3d,
  0x9b, 0xee, 0x95, 0x74, 0x29, 0x7d, 0x56, 0xdb, 0x9d, 0xd4, 0xf4, 0x3e,
  0x49, 0xed, 0xf4, 0x39, 0x9d, 0xfe, 0xbc, 0xa4, 0xe7, 0xd2, 0x57, 0x34,
  0xfd, 0x9a, 0xa6, 0xdf, 0x90, 0x74, 0x37, 0x7d, 0x53, 0xd2, 0x5a, 0x7a,
  0x4c, 0xd2, 0x46, 0xfa, 0x9e, 0xa4, 0x73, 0xe9, 0xfb, 0x92, 0x4e, 0xa7,
  0x27, 0x24, 0x2d, 0xa4, 0x9f, 0x4a, 0x3a, 0x8b, 0x7e, 0x4e, 0x2a, 0x1e,
  0xfd, 0x42, 0xc7, 0xad, 0xe7, 0xb4, 0xfd, 0x0b, 0x92, 0xce, 0xa4, 0x17,
  0x25, 0xb5, 0xd0, 0x7f, 0x49, 0x7a, 0x01, 0xbd, 0x2c, 0x69, 0x09, 0xfd,
  0x46, 0x52, 0x2f, 0xfd, 0x5e, 0xd2, 0x52, 0x7a, 0x4b, 0xe7, 0xff, 0xb3,
  0xa4, 0x53, 0xe9, 0x7f, 0x24, 0x2d, 0xa6, 0xb7, 0x25, 0x55, 0xeb, 0x97,
  0xc7, 0xf5, 0x6f, 0xba, 0x7d, 0x7f, 0xd7, 0xf4, 0x1f, 0x9a, 0xbe, 0x2b,
  0x69, 0xbd, 0x3c, 0xe8, 0xd6, 0x63, 0x66, 0x84, 0x50, 0xe3, 0x63, 0x08,
  0xa5, 0xb7, 0x64, 0xe6, 0x49, 0x53, 0x9b, 0xa6, 0x76, 0x49, 0xd7, 0x93,
  0x43, 0xd2, 0x25, 0x94, 0x27, 0x69, 0x98, 0xf2, 0xb5, 0xdc, 0x29, 0xd4,
  0xf8, 0x14, 0x4a, 0xba, 0x8b, 0xa6, 0x69, 0x3a, 0x53, 0xd2, 0x26, 0xaa,
  0x92, 0x74, 0x19, 0x2d, 0xd0, 0xf4, 0x1c, 0x4d, 0xcf, 0xd5, 0xfa, 0x85,
  0x3a, 0xed, 0xd7, 0xb4, 0x5a, 0xd2, 0x19, 0x54, 0x23, 0xe9, 0x2a, 0x0a,
  0x48, 0xda, 0x49, 0xb5, 0x92, 0x0e, 0xd1, 0x22, 0x49, 0x55, 0x5c, 0xaa,
  0xd7, 0x71, 0x89, 0xd3, 0x4b, 0x24, 0xdd, 0x49, 0x4b, 0x85, 0xda, 0x27,
  0x1a, 0xb4, 0xfd, 0x0a, 0x49, 0xf7, 0xd0, 0x6a, 0x49, 0xfb, 0xa8, 0x43,
  0xd3, 0x0d, 0x7a, 0xdf, 0xd8, 0x24, 0x69, 0x3b, 0x75, 0x49, 0xba, 0x89,
  0x7a, 0x24, 0xdd, 0x41, 0xdb, 0x25, 0x5d, 0x48, 0x3b, 0xb4, 0x7d, 0xaf,
  0xa6, 0x7d, 0x92, 0x56, 0xd3, 0xf9, 0x42, 0xf9, 0x4b, 0x58, 0x28, 0xff,
  0xd9, 0xa3, 0xd3, 0x7b, 0x35, 0x1d, 0xd2, 0x34, 0x22, 0x94, 0xff, 0x5d,
  0xa8, 0xd3, 0xfb, 0x84, 0xf2, 0xc3, 0xa8, 0x50, 0x7e, 0x3f, 0xac, 0xe7,
  0x21, 0x26, 0x94, 0xdf, 0xc7, 0xf5, 0x7c, 0x5c, 0x2c, 0xf8, 0x2c, 0x3e,
  0x87, 0x42, 0x92, 0xce, 0xa3, 0xa4, 0xe0, 0x73, 0xb7, 0x41, 0xe5, 0x92,
  0xfa, 0xe8, 0xa0, 0xe0, 0xf3, 0xb6, 0x8a, 0x5b, 0x2b, 0xb5, 0x7e, 0x15,
  0xfc, 0xe8, 0x61, 0x62, 0x6a, 0xa5, 0x47, 0x24, 0x1d, 0xa6, 0xef, 0x48,
  0xaa, 0xf6, 0x2f, 0x96, 0x9f, 0x2d, 0xe9, 0x7c, 0xea, 0x17, 0x7c, 0x3f,
  0x54, 0xf9, 0x9b, 0x29, 0x4a, 0xa7, 0x24, 0xad, 0xa2, 0x59, 0x82, 0xcf,
  0xe5, 0xbb, 0xa8, 0x40, 0xd2, 0xb3, 0xa8, 0x52, 0xa8, 0x7b, 0x27, 0x2f,
  0xd8, 0xcc, 0x59, 0xbf, 0x18, 0xb8, 0x16, 0x17, 0xc3, 0x1d, 0x9b, 0x54,
  0x9a, 0xef, 0xad, 0x1e, 0xb7, 0xd2, 0xbb, 0x6a, 0xc6, 0xef, 0x3d, 0x21,
  0xad, 0x5f, 0x38, 0x89, 0x3e, 0xae, 0xf5, 0xfe, 0x49, 0xf4, 0x97, 0x6a,
  0x3d, 0xdf, 0x85, 0xdd, 0xa4, 0xf4, 0x53, 0x6a, 0x54, 0xfd, 0xb7, 0xa3,
  0xfe, 0x0f, 0x69, 0x7d, 0x8d, 0xd6, 0x9f, 0x6d, 0x6a, 0xdf, 0x57, 0xa1,
  0xff, 0xae, 0xd6, 0x07, 0xb4, 0x7e, 0xbe, 0x49, 0xff, 0x04, 0xf4, 0x2f,
  0x69, 0x7d, 0xad, 0x96, 0x73, 0xf9, 0x33, 0x75, 0xf9, 0xaf, 0x42, 0x6f,
  0x6c, 0x56, 0xf2, 0x3a, 0x53, 0xfd, 0x99, 0xfc, 0x56, 0x5c, 0x8a, 0x4b,
  0xb5, 0x9e, 0xef, 0x52, 0xe2, 0x34, 0xfd, 0x4c, 0xe8, 0x57, 0x68, 0x3d,
  0xdf, 0xaf, 0xb8, 0x4f, 0xb3, 0x81, 0x4a, 0x5d, 0xfe, 0x62, 0xe8, 0x47,
  0xb5, 0x5e, 0xc8, 0x5f, 0x9c, 0x29, 0x31, 0x50, 0x1c, 0x27, 0x13, 0x6e,
  0x8e, 0x12, 0x45, 0xd8, 0xdd, 0xf2, 0x10, 0x89, 0x71, 0xe7, 0xd4, 0xf2,
  0xfd, 0x8e, 0x14, 0xec, 0x8a, 0xfe, 0x05, 0xfb, 0x91, 0x7f, 0xd1, 0x3e,
  0x29, 0xed, 0xed, 0x78, 0x5a, 0x90, 0x1e, 0x59, 0xa8, 0xfa, 0x3e, 0xe2,
  0x5e, 0x0e, 0xcf, 0x75, 0x82, 0x36, 0x31, 0x15, 0xcb, 0xf8, 0x64, 0x28,
  0x2c, 0x54, 0x55, 0x19, 0x73, 0xff, 0x12, 0x12, 0x97, 0xad, 0xc2, 0x68,
  0x46, 0xa9, 0x2f, 0xc3, 0xcf, 0x2a, 0x2c, 0x65, 0xe4, 0xb5, 0xc6, 0x02,
  0x2f, 0x60, 0x4f, 0xe4, 0x1c, 0x1c, 0xf7, 0x5c, 0x24, 0xd3, 0xc2, 0x69,
  0xe3, 0x34, 0xdb, 0x27, 0x02, 0x6e, 0xb2, 0xd8, 0x62, 0xbe, 0x5f, 0xa3,
  0x7c, 0x8f, 0xe1, 0xb5, 0x79, 0x6c, 0x56, 0xb4, 0x80, 0xef, 0xd7, 0x17,
  0x2f, 0xe4, 0x73, 0x57, 0xa6, 0x8d, 0x7d, 0xa2, 0x88, 0xfa, 0x0c, 0x17,
  0xf5, 0x59, 0x0a, 0x69, 0xc4, 0xb7, 0x19, 0xd6, 0x45, 0xc4, 0xf7, 0xf0,
  0xcc, 0x0d, 0x5d, 0x8d, 0x3b, 0xcb, 0x6c, 0xf8, 0x65, 0xfe, 0x08, 0xf2,
  0x73, 0x9f, 0x92, 0xee, 0x67, 0x91, 0x76, 0x89, 0x3e, 0x51, 0x90, 0xd5,
  0x73, 0xae, 0xe3, 0x0b, 0xd5, 0x7d, 0x3d, 0x28, 0x5c, 0x14, 0x34, 0xb8,
  0xd4, 0x2d, 0x88, 0xc6, 0x45, 0xc8, 0xe3, 0x90, 0xfa, 0x1b, 0x27, 0xd1,
  0x67, 0xf2, 0xdf, 0x3e, 0x89, 0x3e, 0x1f, 0x7a, 0x1e, 0xb3, 0xfb, 0xa0,
  0x8f, 0xb2, 0xbe, 0xd9, 0x45, 0x8b, 0xba, 0x22, 0xa0, 0x05, 0xd8, 0x25,
  0x30, 0x56, 0x03, 0xf7, 0x0f, 0x25, 0x03, 0xcf, 0x50, 0x38, 0xcf, 0x65,
  0xe3, 0xb6, 0xf1, 0x28, 0x4c, 0xcf, 0x33, 0x28, 0xe6, 0x7b, 0x11, 0x77,
  0x34, 0x67, 0x9e, 0x97, 0x1a, 0xf3, 0x0a, 0x69, 0x7a, 0x9e, 0x25, 0x2b,
  0x69, 0x00, 0x5f, 0x65, 0x11, 0x79, 0x55, 0x96, 0x92, 0xbc, 0x35, 0xd8,
  0x57, 0x85, 0xd4, 0x94, 0x62, 0xfc, 0x1b, 0x84, 0x95, 0x4a, 0xf2, 0x56,
  0x50, 0x70, 0x75, 0x21, 0x05, 0xd7, 0x14, 0xc8, 0xd1, 0x35, 0xec, 0x4e,
  0x23, 0xd8, 0x52, 0x40, 0xf7, 0x8f, 0x71, 0xca, 0x62, 0x77, 0xda, 0x63,
  0x81, 0x38, 0xcd, 0xb5, 0x07, 0xdb, 0x0a, 0xa9, 0x21, 0x0f, 0x33, 0xe0,
  0xfe, 0x2f, 0x9e, 0x3b, 0xc7, 0x33, 0x0e, 0xc7, 0xbb, 0xb1, 0xc0, 0x4b,
  0x64, 0x73, 0xb8, 0x30, 0xfe, 0xc3, 0x38, 0xd1, 0xb2, 0x36, 0xd8, 0x5a,
  0x44, 0x15, 0xf6, 0xe9, 0x94, 0x08, 0x94, 0x90, 0x3d, 0x2f, 0x16, 0x78,
  0x88, 0x3e, 0x60, 0x0f, 0xb6, 0x42, 0xde, 0xa6, 0x7a, 0x18, 0x26, 0xaf,
  0xad, 0xaf, 0xb5, 0x40, 0x8e, 0x83, 0x21, 0xfb, 0xf9, 0xe8, 0x42, 0xe5,
  0xcf, 0x31, 0xf7, 0x10, 0x66, 0xce, 0x09, 0x1a, 0x61, 0x6a, 0x5d, 0x86,
  0x16, 0x36, 0x59, 0xd1, 0x72, 0x0f, 0xfb, 0x86, 0x05, 0x33, 0xe0, 0x35,
  0x62, 0x81, 0x5f, 0x61, 0x8c, 0x60, 0xc3, 0xd4, 0xea, 0xb4, 0x8e, 0x04,
  0x8a, 0xc8, 0x62, 0x2d, 0x92, 0xf3, 0xc8, 0x63, 0xfa, 0xa4, 0x1e, 0xd3,
  0x11, 0x77, 0x87, 0xf2, 0x16, 0x5f, 0x42, 0xfa, 0x61, 0x46, 0xff, 0x33,
  0x3d, 0xa7, 0x23, 0xbe, 0xad, 0x58, 0x87, 0x23, 0xbe, 0x2e, 0x3c, 0xd5,
  0x9c, 0xaa, 0xb6, 0xbc, 0xa0, 0xdb, 0x32, 0xe2, 0x2e, 0x44, 0x9a, 0xbd,
  0xce, 0xc5, 0x54, 0xc8, 0xb6, 0x08, 0x53, 0x5b, 0x2c, 0xdc, 0x96, 0x17,
  0x10, 0xd5, 0x9c, 0x72, 0xcc, 0xce, 0x12, 0x4e, 0x0b, 0x8f, 0x92, 0xd5,
  0xa2, 0x7c, 0x9e, 0xcf, 0x26, 0xbf, 0x5f, 0xa8, 0xde, 0x6f, 0x04, 0xbb,
  0x8a, 0x11, 0x8d, 0x2d, 0x58, 0xb7, 0xc1, 0x2e, 0x0f, 0x66, 0x30, 0x9f,
  0xe2, 0xee, 0x15, 0x3c, 0x6b, 0xd4, 0x07, 0x8d, 0x07, 0xfd, 0xe5, 0x59,
  0x76, 0x52, 0x70, 0x8b, 0x87, 0xb8, 0xd4, 0x7d, 0xe8, 0xa1, 0x8b, 0x2a,
  0x44, 0x29, 0x25, 0x7c, 0xc5, 0x28, 0xab, 0x6f, 0x4b, 0x31, 0x4e, 0x25,
  0xd5, 0xd0, 0x7b, 0x29, 0xd8, 0x5d, 0x4c, 0xc1, 0xa0, 0x87, 0x12, 0xcd,
  0xeb, 0xc8, 0xdd, 0xd2, 0xd7, 0xe5, 0x86, 0xb4, 0x18, 0x1e, 0x9a, 0x0f,
  0x3b, 0xa7, 0xa5, 0xc4, 0xea, 0xa5, 0x64, 0xb0, 0x80, 0x44, 0x5d, 0x50,
  0x96, 0xcc, 0x6b, 0xd1, 0x2a, 0xfb, 0xf5, 0x8e, 0x1e, 0x97, 0x44, 0xa0,
  0x91, 0xdc, 0x46, 0x9f, 0xf0, 0x62, 0x1d, 0x78, 0xd0, 0x73, 0x0b, 0xf2,
  0xf1, 0xb8, 0x18, 0x7e, 0xd5, 0xef, 0xa0, 0x8f, 0xdb, 0x9a, 0x4f, 0xc1,
  0xb9, 0x6e, 0xec, 0x7b, 0x36, 0x4a, 0xfa, 0x9c, 0x18, 0x21, 0x58, 0x43,
  0xde, 0xe7, 0xf3, 0xa0, 0xe5, 0xcb, 0x60, 0xbf, 0x1b, 0x28, 0x11, 0x73,
  0x68, 0xb1, 0xdb, 0x0e, 0x5d, 0xcc, 0xd7, 0x83, 0x34, 0xc7, 0x00, 0x43,
  0xf6, 0xbb, 0xd0, 0xaf, 0xde, 0x07, 0x06, 0x77, 0x97, 0x60, 0xfc, 0xf8,
  0xcd, 0x48, 0x01, 0x4d, 0x35, 0x64, 0x6c, 0x34, 0xbc, 0x82, 0x3d, 0xd8,
  0x23, 0x4c, 0x3a, 0x63, 0xa4, 0xf9, 0x22, 0xf2, 0xa5, 0x5c, 0xa8, 0xd7,
  0x81, 0xb1, 0xe0, 0xb7, 0x3c, 0x2e, 0x87, 0xc7, 0x21, 0xeb, 0x30, 0x66,
  0xd3, 0x62, 0xb4, 0xa0, 0x02, 0xbb, 0x52, 0x70, 0x60, 0x0a, 0x5a, 0x8f,
  0x7d, 0xd6, 0x51, 0xe5, 0x08, 0xee, 0x9e, 0x82, 0xb9, 0x5b, 0x42, 0x09,
  0x8c, 0x53, 0x70, 0x40, 0x95, 0x64, 0xa1, 0x02, 0xeb, 0x48, 0xd7, 0xc5,
  0xd4, 0x32, 0xea, 0x74, 0x34, 0x3a, 0x9c, 0xb4, 0xdb, 0x61, 0x50, 0xfd,
  0xd9, 0x36, 0x94, 0xc8, 0xef, 0x36, 0x3d, 0xc2, 0x83, 0x79, 0x51, 0x73,
  0x3c, 0xc3, 0xaf, 0x62, 0x51, 0xb0, 0x79, 0xf2, 0xf6, 0x79, 0xdd, 0x8b,
  0x6c, 0x58, 0x11, 0xad, 0xca, 0xc2, 0xc6, 0xad, 0x0c, 0x5c, 0x42, 0xf3,
  0x2c, 0x2e, 0x5b, 0x55, 0x41, 0xae, 0xf4, 0x52, 0x29, 0x6d, 0xb0, 0x61,
  0xed, 0xb8, 0x7f, 0xce, 0xeb, 0x02, 0x6b, 0x61, 0x3b, 0x6e, 0x6d, 0x2e,
  0x44, 0x22, 0x8f, 0x70, 0x62, 0xfc, 0xf9, 0x7c, 0x3a, 0xdf, 0xaf, 0xde,
  0x01, 0x9e, 0x69, 0x4c, 0x1a, 0x61, 0xe3, 0x75, 0x14, 0x3b, 0x4c, 0x3a,
  0x21, 0x52, 0xe2, 0xb0, 0xe3, 0xba, 0xfd, 0x76, 0x7e, 0x6f, 0xe2, 0x84,
  0xce, 0x22, 0x67, 0x0a, 0xfb, 0x93, 0x5f, 0xbd, 0x2f, 0xac, 0x10, 0x2a,
  0x4a, 0xf2, 0xed, 0x3b, 0xa3, 0x5b, 0xe2, 0x57, 0x73, 0xdc, 0x27, 0x4a,
  0xa0, 0xe3, 0xb7, 0xb9, 0x7d, 0xc6, 0x14, 0xed, 0xfb, 0x72, 0x4f, 0xf1,
  0xf3, 0x3d, 0x95, 0xf5, 0x53, 0x75, 0x4c, 0xf4, 0x8a, 0x9d, 0xf0, 0x32,
  0xf6, 0xff, 0x4c, 0x9c, 0x6e, 0xf5, 0xab, 0x77, 0xb2, 0x15, 0x88, 0x9c,
  0x09, 0xb7, 0x8c, 0x4e, 0x5b, 0xa6, 0x52, 0xd0, 0x53, 0x86, 0xde, 0xdd,
  0x20, 0xa3, 0x60, 0x23, 0x72, 0x67, 0x65, 0xbe, 0x4f, 0x41, 0x36, 0x6e,
  0xf1, 0x31, 0xf6, 0x42, 0xb1, 0xd5, 0xe0, 0xf7, 0xbc, 0x82, 0xaa, 0x5c,
  0x31, 0xdf, 0x3c, 0xd0, 0x98, 0xfb, 0xac, 0x1c, 0xf9, 0x17, 0x8c, 0x2f,
  0xcc, 0x2d, 0xc1, 0xf9, 0xbb, 0x5e, 0x4c, 0xa7, 0x6d, 0x5b, 0x4b, 0xa9,
  0xc1, 0x98, 0x0a, 0xbf, 0xdf, 0x09, 0x2e, 0xb8, 0x15, 0x25, 0x55, 0x94,
  0xc1, 0xcb, 0xa7, 0x62, 0x24, 0x42, 0x72, 0x9d, 0xe9, 0xb9, 0xb5, 0x8c,
  0x04, 0x0e, 0x52, 0x9d, 0x95, 0xed, 0x1b, 0x0d, 0x07, 0xce, 0x66, 0x36,
  0xf2, 0xba, 0x77, 0x76, 0x95, 0xea, 0x3d, 0x89, 0x7f, 0x7a, 0xd0, 0x76,
  0xee, 0x43, 0x10, 0x77, 0x1b, 0xf6, 0x7d, 0x1e, 0x17, 0xf6, 0xed, 0x9d,
  0x7e, 0xb5, 0x4f, 0xf6, 0x89, 0x32, 0xdd, 0xef, 0x0a, 0x51, 0x8b, 0xb5,
  0xb5, 0x93, 0xd7, 0x96, 0x98, 0x86, 0x51, 0x2a, 0x97, 0x63, 0x90, 0xd9,
  0xdb, 0xb8, 0x1c, 0xb5, 0xb7, 0xf5, 0x13, 0x99, 0xf6, 0xbc, 0x71, 0xf9,
  0x80, 0x94, 0x67, 0xd6, 0x4e, 0xc4, 0xcf, 0x91, 0x86, 0xd7, 0x4e, 0x39,
  0xfa, 0x7a, 0xa3, 0x8c, 0x3b, 0xc1, 0xb9, 0xd3, 0x30, 0x3a, 0xe7, 0xca,
  0xe8, 0x92, 0xb1, 0x8b, 0x4d, 0x6a, 0xb7, 0x30, 0xc7, 0x2e, 0xe5, 0x57,
  0x31, 0xaa, 0xdb, 0x37, 0x1d, 0x5e, 0x3e, 0x0a, 0x9d, 0x53, 0xb6, 0x3f,
  0xa3, 0x3f, 0x90, 0xa3, 0xbf, 0x32, 0xab, 0xb7, 0x6a, 0xff, 0xbe, 0xd4,
  0xac, 0x0f, 0x7c, 0x80, 0xdc, 0x16, 0xa7, 0xa5, 0xd8, 0x32, 0x9e, 0xff,
  0xca, 0x9c, 0xfc, 0x63, 0x13, 0xca, 0x3f, 0x9a, 0xa3, 0xbf, 0x6c, 0x82,
  0xfe, 0x9a, 0x1c, 0xfd, 0x07, 0x27, 0xe8, 0x3f, 0x96, 0xa3, 0x3f, 0x9c,
  0xd5, 0xf3, 0xae, 0xc6, 0xe3, 0x77, 0xbd, 0x59, 0xdf, 0x7c, 0x39, 0xe2,
  0x98, 0xcb, 0xe2, 0xb1, 0xa8, 0xf9, 0xe2, 0x71, 0xfe, 0xb4, 0xf6, 0x71,
  0x35, 0x57, 0xbd, 0xf0, 0x92, 0xa2, 0x6c, 0xdf, 0x6e, 0xd7, 0x3a, 0xd5,
  0xb7, 0x2b, 0xd0, 0xb7, 0xa2, 0x6c, 0xb9, 0xf7, 0x9a, 0x75, 0xcd, 0x87,
  0x50, 0xee, 0x78, 0xbe, 0x2f, 0xe4, 0xe4, 0xdb, 0x2f, 0xf3, 0x59, 0xe5,
  0x2f, 0xd1, 0x57, 0xfc, 0x24, 0xe3, 0x56, 0xa2, 0xf9, 0x7a, 0x72, 0xd7,
  0xb9, 0xa4, 0xef, 0x18, 0xda, 0xa7, 0xbe, 0x9e, 0xf1, 0x29, 0xf7, 0x1c,
  0x29, 0xe7, 0x9d, 0x9d, 0xf3, 0x7c, 0xcb, 0xaf, 0x62, 0x7b, 0x77, 0xd7,
  0x2c, 0x44, 0xa5, 0xe3, 0xb8, 0xe3, 0xb8, 0xe4, 0x7d, 0xb5, 0x2f, 0x64,
  0x01, 0xb0, 0x9e, 0x8d, 0x1d, 0xfd, 0x88, 0x8d, 0x7f, 0x52, 0x31, 0x8d,
  0x3f, 0x9d, 0x70, 0x5a, 0xab, 0x0c, 0xb1, 0x78, 0xc7, 0x60, 0x1e, 0xe2,
  0x9c, 0x5d, 0xee, 0x71, 0x90, 0x59, 0x76, 0x0c, 0x38, 0x60, 0xef, 0xe4,
  0x77, 0x64, 0x5d, 0x3b, 0x42, 0x36, 0xe8, 0x78, 0xff, 0xe3, 0x4f, 0x31,
  0x9c, 0x62, 0xc4, 0x7d, 0x1d, 0xaf, 0x1b, 0x94, 0x94, 0x8f, 0x1d, 0xb5,
  0x86, 0xbc, 0x9e, 0x44, 0x73, 0x37, 0x6e, 0x15, 0x7d, 0x3d, 0x33, 0xc9,
  0x63, 0x1f, 0x1f, 0xef, 0x9f, 0xf8, 0xd5, 0x39, 0x27, 0xe6, 0xfe, 0x08,
  0xd2, 0xdc, 0x8e, 0xa9, 0x22, 0xe6, 0x33, 0x30, 0xee, 0x2e, 0x9c, 0xfa,
  0xcf, 0xd1, 0xfd, 0x51, 0xfb, 0xdf, 0x33, 0xba, 0xaf, 0x23, 0xbe, 0xa7,
  0x4c, 0xf3, 0x62, 0x93, 0xb2, 0x5f, 0x66, 0xc6, 0x21, 0xf8, 0x08, 0xc6,
  0x41, 0xe9, 0xec, 0xf2, 0x97, 0xe8, 0xd7, 0x5a, 0x37, 0x66, 0xff, 0xac,
  0xdc, 0xab, 0x8a, 0xf5, 0xfa, 0xca, 0xfc, 0x70, 0xd9, 0x5e, 0x4f, 0xb1,
  0xc8, 0x8c, 0xdb, 0x6b, 0x7a, 0xdc, 0xb6, 0xb9, 0x7d, 0xd2, 0xd6, 0xd0,
  0x6b, 0xe8, 0x4f, 0x7e, 0x92, 0xf7, 0x84, 0x98, 0xfb, 0x26, 0xee, 0x1b,
  0xc9, 0xd8, 0xe7, 0x2e, 0xc6, 0x2e, 0x52, 0x8c, 0x94, 0x21, 0xfd, 0xe2,
  0x1d, 0xbf, 0xfa, 0xcc, 0x20, 0x78, 0x68, 0x06, 0xec, 0x16, 0xcb, 0xfa,
  0x1a, 0x68, 0x1a, 0x75, 0x5f, 0x3e, 0x0b, 0xe9, 0xe9, 0x88, 0x61, 0xd8,
  0x6b, 0xdd, 0xb3, 0x99, 0x5a, 0x63, 0x98, 0x97, 0x7c, 0x8e, 0xb9, 0xee,
  0x19, 0xa0, 0x05, 0xf6, 0xfd, 0x8e, 0x4f, 0xf3, 0x9b, 0xc8, 0x69, 0xc5,
  0xf9, 0xde, 0xfc, 0xe2, 0x7c, 0x8e, 0xb2, 0x16, 0xd9, 0xfe, 0x77, 0xfd,
  0xea, 0xee, 0xd1, 0x7d, 0x68, 0x56, 0x6e, 0xdc, 0x85, 0x55, 0xcc, 0x7d,
  0x15, 0xe2, 0xa6, 0xb7, 0xd9, 0xeb, 0xa9, 0xcb, 0xf7, 0xe1, 0xbe, 0x5c,
  0x4e, 0x75, 0xf9, 0x53, 0x41, 0xa7, 0x81, 0x7a, 0xa9, 0xfb, 0x4a, 0xae,
  0xb5, 0x0c, 0x6d, 0xc0, 0x39, 0xc8, 0x3d, 0x95, 0xa9, 0xc3, 0x71, 0x85,
  0xb8, 0x6e, 0xcc, 0x7e, 0x1b, 0xda, 0x5b, 0x2c, 0xc4, 0x75, 0xf1, 0x40,
  0x15, 0x6d, 0x77, 0x3a, 0x65, 0x49, 0x47, 0x50, 0x12, 0xbf, 0x17, 0x75,
  0xe9, 0xb8, 0xef, 0xa9, 0x56, 0x9f, 0x9d, 0x99, 0xeb, 0x55, 0x7b, 0x4c,
  0xb1, 0x68, 0xcc, 0x0f, 0xa8, 0x9d, 0xd4, 0x98, 0x45, 0xf5, 0x3e, 0x9e,
  0xf7, 0x29, 0x68, 0xaf, 0x93, 0xbc, 0x67, 0xd5, 0x05, 0x70, 0xd2, 0x98,
  0xbb, 0xdb, 0x89, 0x1d, 0xec, 0x1c, 0xae, 0xbd, 0x14, 0x72, 0x97, 0xb3,
  0xc1, 0x59, 0x96, 0xe5, 0x63, 0xbe, 0xe7, 0x69, 0x3a, 0x5a, 0xa4, 0x5a,
  0x37, 0x95, 0xf3, 0x99, 0x5a, 0xc5, 0xfd, 0x97, 0x2d, 0x6b, 0x5e, 0x40,
  0xdb, 0x1f, 0xe4, 0x96, 0x39, 0x50, 0x23, 0xcf, 0x5f, 0x45, 0xb5, 0xfa,
  0x0c, 0xac, 0xbb, 0x59, 0xb7, 0x07, 0x6e, 0xd1, 0x68, 0x60, 0x1c, 0x6c,
  0xc5, 0x36, 0xee, 0xa5, 0x1d, 0x65, 0x26, 0x7a, 0x6e, 0x27, 0xeb, 0x16,
  0x6f, 0x69, 0xb1, 0x8d, 0xfb, 0xa1, 0xe6, 0xe4, 0x1c, 0xe4, 0x8b, 0x71,
  0xbe, 0x5b, 0x26, 0xf6, 0x23, 0xe6, 0x2e, 0x97, 0xed, 0xe6, 0x39, 0x28,
  0xa0, 0x02, 0xc7, 0xd3, 0xf4, 0x2e, 0x5a, 0xd0, 0x40, 0xeb, 0xa8, 0xee,
  0xf8, 0x22, 0xf2, 0x56, 0xd4, 0xf9, 0xce, 0x26, 0x6f, 0x5d, 0x9d, 0x6f,
  0x06, 0x79, 0xb7, 0xd6, 0xe1, 0x1c, 0xe1, 0xed, 0xaf, 0xf3, 0x71, 0xbe,
  0x0a, 0xdc, 0xf6, 0x12, 0xfc, 0xe1, 0x3a, 0x4e, 0x50, 0x27, 0xe9, 0x41,
  0x2a, 0xce, 0xaf, 0xc0, 0xfd, 0x2d, 0xe1, 0x6e, 0xcd, 0x91, 0x8c, 0xdb,
  0xdc, 0xa3, 0x25, 0x0b, 0x21, 0x69, 0x31, 0x49, 0xba, 0x6f, 0xc5, 0x18,
  0xf8, 0x66, 0xf1, 0xbb, 0x4c, 0x2b, 0xfb, 0x45, 0x81, 0xf4, 0x87, 0x39,
  0x4c, 0xe1, 0x0f, 0x77, 0xf3, 0x2c, 0xbd, 0x8f, 0xcd, 0x9d, 0xd2, 0xc6,
  0xa6, 0x3d, 0x7a, 0x4d, 0xb5, 0xfa, 0xcc, 0x30, 0x11, 0xf8, 0x28, 0x76,
  0x9c, 0x02, 0x0b, 0x7f, 0x36, 0x58, 0x0b, 0x4d, 0x03, 0xe6, 0xb6, 0x02,
  0x37, 0xb4, 0x44, 0x20, 0x4c, 0x01, 0x2b, 0xce, 0x6a, 0x88, 0x5a, 0x13,
  0xd7, 0xd5, 0x0f, 0xb2, 0xeb, 0x6a, 0xa2, 0xee, 0x87, 0xef, 0xa1, 0x7b,
  0xe2, 0x3d, 0x74, 0x3f, 0x36, 0xc5, 0x58, 0xd5, 0xc6, 0xf6, 0x6a, 0xad,
  0x0b, 0xfc, 0x27, 0xce, 0x73, 0x93, 0xe5, 0x7b, 0x32, 0x9b, 0x2f, 0xb3,
  0x47, 0xf2, 0x0f, 0xdf, 0x81, 0xcf, 0x95, 0xa7, 0x11, 0x5e, 0x75, 0x53,
  0xe8, 0x72, 0xf6, 0x59, 0xf2, 0x06, 0x98, 0x9f, 0x2b, 0xf9, 0x29, 0x88,
  0x19, 0x4c, 0x4b, 0xc8, 0xe0, 0xf9, 0xf2, 0xb1, 0x44, 0xa8, 0x92, 0x84,
  0x43, 0x96, 0xc1, 0x9f, 0x8b, 0xf2, 0xb8, 0xb0, 0x2f, 0x71, 0xf9, 0xfc,
  0x3d, 0xa4, 0x7c, 0x52, 0xf5, 0x9e, 0xde, 0xc6, 0x44, 0xe0, 0xe3, 0x68,
  0xa3, 0x2b, 0xbb, 0x27, 0xe7, 0xea, 0xae, 0xc9, 0xea, 0x4e, 0x8f, 0xc7,
  0x23, 0xcd, 0x3f, 0xca, 0xc6, 0x63, 0x8b, 0x6e, 0xff, 0x33, 0x3a, 0xae,
  0x74, 0x63, 0x2e, 0xdd, 0x32, 0x1e, 0x3b, 0xc8, 0xa1, 0xfb, 0xa5, 0xee,
  0x9d, 0xfc, 0xd6, 0xae, 0xe8, 0x0c, 0xf2, 0x3b, 0x27, 0x91, 0xdf, 0x4d,
  0xea, 0xfe, 0xaa, 0xee, 0x5c, 0x9b, 0xab, 0xd5, 0x67, 0xc6, 0x09, 0xf8,
  0x6c, 0x0b, 0x66, 0xbb, 0x00, 0xbe, 0xc6, 0xeb, 0xb8, 0x2f, 0x30, 0x17,
  0xa7, 0x86, 0x3a, 0xb4, 0xf7, 0x02, 0xaa, 0xb5, 0xf4, 0xd5, 0xce, 0x46,
  0x2a, 0x80, 0xd4, 0x79, 0x32, 0x35, 0x47, 0xc6, 0x5e, 0xbe, 0xa1, 0x4c,
  0x37, 0xbe, 0x40, 0x1c, 0x7b, 0x71, 0x82, 0x17, 0x73, 0x44, 0x25, 0xf5,
  0xd5, 0xce, 0x20, 0xdf, 0x6a, 0xc4, 0x75, 0x91, 0x47, 0x73, 0xac, 0x38,
  0x8d, 0xfa, 0xf8, 0x8e, 0x5f, 0xe5, 0x8c, 0xb9, 0x05, 0xea, 0x77, 0x59,
  0xc7, 0x65, 0xbd, 0x4b, 0x66, 0xf1, 0x6d, 0xd7, 0xf7, 0x3d, 0xd4, 0xbb,
  0xb3, 0xde, 0x47, 0xde, 0xd2, 0x98, 0xef, 0x9b, 0xd4, 0x0d, 0xed, 0xb7,
  0xe4, 0xf3, 0x31, 0xc4, 0xaf, 0x0a, 0x5b, 0x3e, 0xda, 0xc3, 0x2b, 0xb9,
  0xc4, 0x3e, 0x85, 0xce, 0xda, 0xd3, 0x4a, 0xf3, 0xed, 0xfc, 0x89, 0x73,
  0xcc, 0x67, 0xc5, 0xbd, 0xaa, 0xc2, 0xee, 0x44, 0xbb, 0x6d, 0x38, 0xbf,
  0xc5, 0x7c, 0x0e, 0x44, 0x16, 0xaf, 0x2d, 0x16, 0x78, 0x94, 0x5a, 0x6c,
  0x23, 0x72, 0x04, 0x5d, 0x28, 0xdb, 0x8b, 0x7a, 0x70, 0xd2, 0xb1, 0x58,
  0xe5, 0x67, 0xdf, 0xe3, 0x3f, 0x87, 0x56, 0xd1, 0xbf, 0x94, 0x3e, 0xfd,
  0x47, 0xe9, 0xcd, 0x73, 0xcb, 0x63, 0x3b, 0x12, 0xf8, 0x29, 0xe6, 0xb6,
  0x68, 0x82, 0x3c, 0x11, 0xb8, 0x43, 0xca, 0xcd, 0xf3, 0x2d, 0xed, 0x9b,
  0x9f, 0xc6, 0x7c, 0x4f, 0xb4, 0x1f, 0x09, 0xfc, 0x44, 0xda, 0xdb, 0xf4,
  0x19, 0x75, 0xb4, 0x5a, 0xed, 0x77, 0xb9, 0x31, 0xcc, 0x82, 0x9e, 0x25,
  0x02, 0x9f, 0x21, 0xab, 0x28, 0x32, 0xf9, 0xcb, 0xc5, 0xda, 0xcf, 0xd8,
  0x57, 0x7b, 0xe1, 0x33, 0x19, 0x1d, 0xaf, 0x93, 0x43, 0x7a, 0x9d, 0xc7,
  0xdc, 0xd7, 0xca, 0x7d, 0x93, 0xa3, 0x59, 0x11, 0x4e, 0x64, 0x33, 0xe5,
  0xcd, 0x27, 0xe6, 0x0e, 0xf2, 0xd9, 0xd5, 0xb7, 0x8a, 0x7c, 0xd2, 0x6f,
  0x54, 0xfc, 0x3c, 0x5a, 0xad, 0xbe, 0x37, 0x70, 0x86, 0xba, 0x7b, 0x6e,
  0x45, 0xd4, 0xd4, 0x63, 0x6d, 0xe3, 0xb1, 0x6e, 0x85, 0xd4, 0x8d, 0x7c,
  0x7c, 0x8a, 0x3e, 0x5e, 0xad, 0x3e, 0x5b, 0xe3, 0x18, 0x59, 0x84, 0x7d,
  0xaa, 0xfb, 0x47, 0x98, 0xed, 0x3c, 0x8e, 0x48, 0x1f, 0xd6, 0xbb, 0x59,
  0x91, 0xde, 0xcd, 0x40, 0x6d, 0x8e, 0x37, 0x0e, 0xe4, 0x0d, 0x4a, 0xeb,
  0x99, 0x9c, 0x2e, 0xf6, 0x4e, 0x5b, 0x7a, 0x33, 0x62, 0xe8, 0xdc, 0xb3,
  0xa6, 0xb7, 0xa1, 0x45, 0x9f, 0xa0, 0xfb, 0x48, 0x7c, 0xb2, 0xfe, 0xaf,
  0xb3, 0x89, 0x4b, 0xe1, 0x32, 0xbe, 0xce, 0x65, 0xf8, 0x7c, 0x4c, 0xad,
  0x6b, 0x6d, 0xce, 0xbc, 0x2b, 0xb6, 0x7d, 0x3b, 0x18, 0xf3, 0xcd, 0xe5,
  0xb4, 0x6d, 0xad, 0xcb, 0x99, 0x7f, 0xc5, 0x13, 0xdf, 0x7e, 0x4c, 0x95,
  0xf8, 0x4c, 0x41, 0x81, 0xa8, 0x7a, 0xa9, 0x88, 0x5c, 0xba, 0x5d, 0x9f,
  0xae, 0x56, 0x77, 0x35, 0x6e, 0x97, 0x13, 0xed, 0x8a, 0xb9, 0xa7, 0xf1,
  0x0e, 0x47, 0x1c, 0xdb, 0xa7, 0x92, 0x28, 0xe9, 0xfe, 0xa8, 0xaa, 0x61,
  0x99, 0x6e, 0xa5, 0x53, 0xb7, 0xd2, 0xc9, 0xad, 0xbc, 0x5f, 0x95, 0x89,
  0x13, 0xb2, 0xc5, 0x71, 0xbf, 0x68, 0x12, 0x25, 0x68, 0xa1, 0x47, 0xb5,
  0x70, 0x1a, 0x39, 0xa6, 0x70, 0x5e, 0x51, 0xcf, 0xb9, 0x1f, 0xd4, 0xed,
  0x03, 0xcd, 0x5b, 0x6b, 0xb3, 0xda, 0xd0, 0xbe, 0xed, 0xdc, 0x3e, 0xa4,
  0x9d, 0xde, 0x19, 0x6b, 0x0b, 0xac, 0x05, 0x57, 0x3c, 0x74, 0xa7, 0xcd,
  0x59, 0x20, 0x0e, 0x67, 0x4a, 0xb4, 0xea, 0xb9, 0x3e, 0x59, 0xcd, 0x9f,
  0x81, 0xa9, 0x39, 0xb2, 0x64, 0xe7, 0x28, 0xe6, 0x3e, 0x91, 0x7d, 0x1f,
  0xb0, 0x12, 0xbe, 0x11, 0x0c, 0xcc, 0xc6, 0x7d, 0x61, 0x37, 0x91, 0x9e,
  0xdf, 0xf1, 0x73, 0x49, 0xe6, 0x9d, 0xce, 0x99, 0xde, 0xf3, 0x64, 0xee,
  0x83, 0x5f, 0x3c, 0xdd, 0x9f, 0x6c, 0x98, 0x53, 0x9b, 0xf2, 0xa7, 0x9b,
  0xb5, 0x3f, 0x65, 0x6c, 0x1f, 0x7c, 0x0f, 0xdb, 0x5b, 0xb2, 0xbe, 0xf7,
  0xcf, 0xd5, 0x3f, 0x59, 0x9b, 0xd8, 0xcf, 0x1e, 0xa9, 0x56, 0x71, 0x75,
  0xa2, 0x9f, 0x05, 0xd7, 0xcc, 0xa5, 0xc4, 0xd6, 0x7b, 0xe1, 0x6b, 0x6c,
  0xef, 0xd0, 0x67, 0xdf, 0xc7, 0x27, 0xb1, 0xaf, 0xb2, 0x2f, 0x6a, 0xb5,
  0xe1, 0x64, 0x7b, 0x35, 0x59, 0x43, 0xaa, 0x7c, 0xfb, 0x84, 0x3a, 0x33,
  0xe7, 0xbf, 0x27, 0x75, 0x19, 0xf1, 0xe0, 0x39, 0x58, 0x87, 0xdd, 0x02,
  0x25, 0xa1, 0x23, 0xb5, 0x16, 0x61, 0x69, 0xb0, 0xa0, 0x8c, 0xc0, 0xcf,
  0xe4, 0x2a, 0xe4, 0x3b, 0xa6, 0x7a, 0xa7, 0xf0, 0x8b, 0x6a, 0xf5, 0x9d,
  0x03, 0xbe, 0xfb, 0x36, 0x38, 0x6c, 0x3c, 0x4f, 0xef, 0x56, 0x19, 0xde,
  0x37, 0x62, 0xbe, 0x6a, 0x8e, 0x50, 0x34, 0x9b, 0x76, 0xe3, 0x3c, 0xe8,
  0x35, 0x96, 0xe0, 0x0c, 0x17, 0x73, 0x7f, 0x92, 0xe3, 0x1d, 0xf6, 0xd0,
  0x6a, 0x2a, 0xb1, 0x9d, 0x25, 0x35, 0x4b, 0x4a, 0x61, 0x85, 0x45, 0x8d,
  0x73, 0xf1, 0xbc, 0xe7, 0x6d, 0xb6, 0xf2, 0x06, 0xdc, 0x72, 0xc5, 0xd6,
  0x64, 0xa0, 0x96, 0x7c, 0xb6, 0x06, 0x7b, 0x11, 0x8d, 0xc8, 0xb7, 0xb1,
  0x4e, 0x5b, 0xd2, 0xb7, 0x88, 0xba, 0x10, 0x0f, 0x93, 0xbe, 0x3a, 0x50,
  0xb3, 0x3c, 0xc0, 0xf2, 0x79, 0x19, 0x39, 0xcf, 0x43, 0xd5, 0xea, 0x0a,
  0x52, 0x37, 0x63, 0xf6, 0x19, 0xbf, 0x7c, 0x37, 0xc6, 0xef, 0x06, 0xbb,
  0x88, 0x9f, 0xcd, 0x90, 0xfd, 0x46, 0xae, 0xcf, 0xa4, 0xfb, 0xbf, 0xe5,
  0x7b, 0xc8, 0x06, 0x5a, 0x40, 0x49, 0xf7, 0x2b, 0xf2, 0x6d, 0xcc, 0x1c,
  0x9a, 0x45, 0x25, 0xb8, 0x6d, 0xec, 0xc6, 0xae, 0xbe, 0x04, 0x13, 0x5b,
  0x22, 0xdc, 0x84, 0xb6, 0xcd, 0xfd, 0xa9, 0x87, 0x7c, 0x31, 0x37, 0x7f,
  0xc3, 0xc6, 0x69, 0x69, 0xb0, 0xdb, 0xe8, 0xe9, 0x45, 0xff, 0xfb, 0x7a,
  0x95, 0xe5, 0xa7, 0x8b, 0xec, 0xee, 0x06, 0x87, 0x95, 0xbe, 0x5c, 0x5b,
  0x65, 0xb9, 0xc4, 0xf3, 0xa5, 0xda, 0x98, 0x6f, 0x3e, 0x56, 0x7b, 0xd5,
  0x53, 0x45, 0x93, 0xce, 0x35, 0x4b, 0xdf, 0xa9, 0x56, 0xfb, 0x24, 0xbf,
  0x77, 0xf3, 0xa2, 0xe7, 0xde, 0xd5, 0x31, 0xdf, 0xe3, 0xfa, 0x1d, 0x54,
  0xe6, 0x5d, 0xcd, 0x3f, 0x74, 0x8c, 0x61, 0x9f, 0x27, 0x79, 0xe3, 0x96,
  0x3e, 0x8f, 0x48, 0x24, 0xe4, 0xfb, 0xa1, 0x66, 0x12, 0x46, 0x50, 0xb0,
  0xc7, 0xef, 0x92, 0xef, 0xb6, 0x64, 0x0d, 0x36, 0x59, 0x5d, 0x11, 0xbd,
  0x63, 0x85, 0x68, 0xc3, 0x4d, 0x9d, 0xbd, 0x74, 0x83, 0x95, 0x0b, 0x2b,
  0x5a, 0xee, 0xf7, 0x57, 0xd3, 0x83, 0x56, 0xab, 0x52, 0xdf, 0x96, 0x61,
  0x3e, 0x6f, 0xd5, 0x8e, 0x50, 0x44, 0xf7, 0x64, 0x64, 0x0f, 0x6b, 0xe6,
  0xae, 0x63, 0x62, 0xaa, 0xe7, 0xae, 0x53, 0xed, 0x2b, 0x44, 0xc9, 0x94,
  0x3b, 0x8f, 0xd0, 0x2f, 0xad, 0x68, 0x39, 0xca, 0xec, 0xdb, 0xb0, 0x9e,
  0x8e, 0xd8, 0x98, 0xa7, 0xab, 0x25, 0x59, 0x4e, 0xbf, 0xd7, 0xaa, 0xde,
  0x0d, 0xed, 0x74, 0xab, 0x8d, 0x8a, 0x76, 0x6e, 0x38, 0xb8, 0xe1, 0xc0,
  0xc5, 0x3f, 0x3e, 0x45, 0x37, 0xd9, 0x74, 0xe5, 0xf4, 0x35, 0x88, 0x8f,
  0x74, 0xfa, 0x03, 0x2b, 0x0e, 0xd0, 0x1d, 0x0e, 0xb4, 0xed, 0xa5, 0xc7,
  0xce, 0xbf, 0xf0, 0xd8, 0xbe, 0x47, 0x37, 0xd0, 0x13, 0x9c, 0x12, 0x1e,
  0xcf, 0xa9, 0xc7, 0xe8, 0x17, 0x0e, 0x69, 0xfd, 0x12, 0x7d, 0xdb, 0x21,
  0x8b, 0xff, 0xb4, 0x24, 0xbd, 0xf4, 0x8a, 0x05, 0x26, 0x11, 0x7a, 0x1d,
  0xfd, 0xef, 0xbb, 0xe7, 0xc0, 0xd3, 0xcb, 0x5f, 0xee, 0xf3, 0x23, 0xc3,
  0x01, 0x7a, 0x8a, 0xe5, 0xf4, 0x33, 0x0b, 0x5b, 0x19, 0x4b, 0x77, 0x18,
  0x1d, 0xfb, 0xe9, 0x97, 0x3c, 0x46, 0xbf, 0xe2, 0xc7, 0x71, 0x7e, 0x17,
  0xf5, 0x09, 0x7e, 0xdc, 0x60, 0xb0, 0xd9, 0x47, 0x99, 0xfd, 0x18, 0x3f,
  0x6e, 0xe4, 0xc7, 0xf5, 0xfc, 0xb8, 0xd6, 0x90, 0xf5, 0x7c, 0x58, 0x1a,
  0x5c, 0x27, 0x9f, 0x1f, 0x57, 0xa2, 0x9b, 0x64, 0xa2, 0x47, 0xb6, 0x87,
  0x7e, 0xe7, 0xc0, 0xe3, 0x59, 0x1b, 0x24, 0x17, 0x6e, 0x58, 0xde, 0x7b,
  0x47, 0x64, 0xc3, 0xc6, 0x23, 0xd5, 0xf4, 0x02, 0x17, 0xd0, 0x23, 0xad,
  0xf4, 0xb8, 0xf5, 0x64, 0x06, 0xff, 0x66, 0x96, 0xfe, 0xd8, 0x8e, 0xc7,
  0x15, 0x5c, 0xcc, 0x51, 0xfa, 0xb8, 0x6c, 0xe2, 0xbd, 0x86, 0xe7, 0xf5,
  0xea, 0x0d, 0x61, 0x63, 0x74, 0xc7, 0x4e, 0xfa, 0x86, 0x45, 0x16, 0xfd,
  0xd8, 0x4b, 0x77, 0x1e, 0xad, 0x09, 0x1b, 0x17, 0xed, 0xa7, 0x2f, 0x49,
  0x93, 0xbb, 0xe8, 0x19, 0x81, 0x1c, 0x77, 0x6d, 0x30, 0x4a, 0x45, 0x79,
  0xd1, 0x8d, 0x46, 0xfa, 0xba, 0x1b, 0x8d, 0x03, 0xd7, 0x09, 0xaf, 0x93,
  0xee, 0xe7, 0x92, 0xee, 0xa0, 0x1e, 0xd9, 0xba, 0x3e, 0x99, 0xd9, 0xf8,
  0x2e, 0x35, 0x19, 0x7f, 0x30, 0xf6, 0x1b, 0x3f, 0xb1, 0xec, 0x3f, 0x60,
  0xbc, 0x73, 0xe0, 0xc5, 0xce, 0xe8, 0x0d, 0xcb, 0x97, 0xaf, 0x58, 0xbe,
  0x7c, 0xe5, 0xc1, 0x0b, 0x96, 0x5f, 0xbf, 0x82, 0x8e, 0x61, 0x18, 0x6e,
  0xa0, 0x43, 0x02, 0x27, 0xe5, 0x97, 0xd1, 0xd8, 0x4b, 0x36, 0xac, 0xa0,
  0x6b, 0xb9, 0xf4, 0x1b, 0x56, 0xd0, 0x29, 0x21, 0x27, 0x4c, 0x94, 0xb8,
  0x8f, 0xf9, 0xf7, 0xd1, 0x63, 0x2a, 0x75, 0x4c, 0x94, 0x7b, 0xfd, 0x9d,
  0xf4, 0x2e, 0xdb, 0x1e, 0xa1, 0xdf, 0xd8, 0xd9, 0x94, 0xae, 0xe1, 0xe9,
  0xb9, 0x91, 0xae, 0x92, 0x19, 0xe9, 0x72, 0x3b, 0x5b, 0x7e, 0x85, 0xde,
  0xb4, 0xa9, 0x3e, 0xaf, 0x38, 0x42, 0xd7, 0xda, 0xb9, 0x31, 0x1f, 0xdc,
  0xd9, 0x77, 0xec, 0xa9, 0xf3, 0x8f, 0x6c, 0x3e, 0x62, 0xb8, 0xf7, 0xf7,
  0x1e, 0x58, 0x21, 0xbc, 0xee, 0x3b, 0x85, 0xa7, 0x8c, 0x7e, 0x86, 0x42,
  0x76, 0xd0, 0x9b, 0x86, 0x6c, 0xef, 0x65, 0x1b, 0x96, 0x67, 0xd6, 0xc2,
  0x22, 0x52, 0x77, 0xc5, 0x12, 0xde, 0x5d, 0x40, 0xe7, 0x90, 0x3a, 0xcf,
  0xcd, 0x84, 0xef, 0x67, 0xbe, 0x6b, 0x27, 0xb4, 0x4d, 0xe6, 0xbd, 0x8b,
  0x91, 0x85, 0x4b, 0xa6, 0x5d, 0xda, 0x26, 0xf3, 0xfd, 0xbd, 0x26, 0x4d,
  0xeb, 0x35, 0xcd, 0xcb, 0xda, 0xab, 0x3d, 0xa4, 0x5e, 0xdf, 0xe6, 0x59,
  0x36, 0x4b, 0x97, 0x59, 0xa5, 0x6d, 0xeb, 0xb4, 0x3c, 0x63, 0xb3, 0x4a,
  0xb7, 0x27, 0x73, 0x5f, 0x65, 0x78, 0xb4, 0xcd, 0x2a, 0x5d, 0x5e, 0xa6,
  0x5d, 0xd6, 0x2c, 0x2f, 0x74, 0x7b, 0x0b, 0xe4, 0x32, 0xcc, 0xdc, 0x81,
  0x0d, 0x6d, 0x63, 0x98, 0x6c, 0x0c, 0xbd, 0x8f, 0xf0, 0xad, 0xaa, 0x20,
  0xdb, 0xce, 0x55, 0x9a, 0xae, 0xd1, 0x74, 0xad, 0x2c, 0xc1, 0xa2, 0xf5,
  0xb8, 0x2b, 0x99, 0xea, 0x53, 0xef, 0x31, 0x2c, 0x92, 0xae, 0xd5, 0xf5,
  0xaa, 0xf7, 0x29, 0x4c, 0xf3, 0x35, 0x2d, 0xd4, 0x79, 0x3d, 0x38, 0xf1,
  0x59, 0xe4, 0x58, 0x8d, 0xb7, 0x79, 0x0a, 0xad, 0x94, 0x29, 0xbb, 0x89,
  0xcf, 0xf4, 0xa9, 0x5c, 0xe7, 0x9b, 0x81, 0x99, 0x12, 0xa4, 0xde, 0x59,
  0x0a, 0x1a, 0xff, 0xce, 0xe2, 0x2c, 0xd4, 0xc9, 0xe5, 0xcd, 0x05, 0x5d,
  0xab, 0xdb, 0x51, 0x2f, 0x6b, 0xc9, 0x8c, 0x63, 0xbd, 0x96, 0xad, 0x95,
  0x32, 0xab, 0x9c, 0x9f, 0xf1, 0xf2, 0x57, 0x6a, 0xd9, 0x4a, 0xd3, 0x98,
  0xac, 0x94, 0x29, 0xf5, 0x5d, 0x3d, 0xa6, 0x5c, 0xae, 0x4d, 0xd2, 0xf1,
  0x7c, 0x8c, 0x56, 0x4d, 0xdb, 0x74, 0xbd, 0xac, 0x29, 0x36, 0xf1, 0xd3,
  0xb3, 0x7e, 0x33, 0xdd, 0x34, 0xee, 0xc5, 0xd9, 0xf9, 0x9c, 0xa7, 0xf5,
  0x6e, 0x5d, 0xe6, 0x0c, 0x5d, 0x4f, 0x7d, 0xd6, 0x92, 0xf4, 0x77, 0x0b,
  0x32, 0xd6, 0x22, 0x9f, 0x84, 0x93, 0x44, 0x21, 0xcd, 0xaf, 0x4c, 0x36,
  0x54, 0x46, 0x43, 0xc3, 0xfd, 0x83, 0xa1, 0xca, 0x96, 0x3a, 0x7f, 0x64,
  0x6b, 0xdd, 0x68, 0x5b, 0x4f, 0xed, 0xe8, 0xde, 0xfd, 0x4b, 0x0f, 0x2e,
  0x4a, 0x8e, 0x76, 0x24, 0x97, 0x6e, 0x1c, 0xab, 0x5b, 0x37, 0xda, 0x9e,
  0x63, 0x77, 0x61, 0xe7, 0x58, 0xbc, 0xeb, 0xe0, 0xa6, 0xc5, 0xfb, 0x3b,
  0xf6, 0xaf, 0xeb, 0x0f, 0xb4, 0xed, 0x58, 0xb3, 0xae, 0xbe, 0x7e, 0x75,
  0xc3, 0x96, 0xae, 0xf5, 0xdd, 0xb9, 0x76, 0xd1, 0xed, 0x0d, 0x81, 0xb5,
  0x43, 0x03, 0x4b, 0x1a, 0xba, 0x0e, 0x1c, 0xe8, 0xe9, 0x5d, 0x7a, 0xd1,
  0xe2, 0x1d, 0xfb, 0xd7, 0x8f, 0x5e, 0x38, 0xd2, 0x1f, 0x3e, 0x2f, 0x85,
  0xbd, 0x91, 0x8c, 0xaa, 0x0e, 0x12, 0x0b, 0xc8, 0xbe, 0x3c, 0x12, 0x8b,
  0xa4, 0x57, 0x92, 0xb1, 0xb2, 0x89, 0xac, 0x2b, 0x9b, 0xf0, 0xb4, 0xf3,
  0x73, 0x41, 0x0f, 0x15, 0xb6, 0x0c, 0x85, 0x62, 0x7b, 0xc3, 0xe7, 0x85,
  0xd2, 0x03, 0x43, 0xe1, 0x24, 0x4d, 0x6d, 0x89, 0x0f, 0x27, 0xe2, 0xb1,
  0x70, 0x2c, 0xdd, 0x15, 0x0e, 0x27, 0x7b, 0x22, 0xe1, 0xfd, 0xd5, 0x17,
  0x86, 0xc6, 0x42, 0xe4, 0x6c, 0x89, 0xc7, 0x62, 0xe1, 0x81, 0x74, 0x24,
  0x1e, 0x23, 0xef, 0xda, 0x86, 0xca, 0xca, 0xee, 0x83, 0xb1, 0xf4, 0x50,
  0x38, 0x1d, 0x19, 0x68, 0x89, 0x86, 0x52, 0xa8, 0xaa, 0x8d, 0x8c, 0xb6,
  0x76, 0x12, 0xed, 0x64, 0xb4, 0x2f, 0x00, 0xda, 0xc9, 0xd2, 0xde, 0xce,
  0x89, 0x0e, 0x30, 0x1d, 0x9d, 0x60, 0x3a, 0x49, 0x74, 0x90, 0xd1, 0xc1,
  0xe8, 0xa4, 0x59, 0x1d, 0xa3, 0x03, 0xe1, 0xd5, 0x03, 0x03, 0xe1, 0x54,
  0x2a, 0xd2, 0x1f, 0x89, 0x46, 0xd2, 0x07, 0x37, 0xc5, 0x07, 0xc3, 0x5d,
  0xc9, 0xf8, 0x58, 0x64, 0x10, 0xad, 0x28, 0xdb, 0x10, 0x3e, 0xd8, 0x1f,
  0x0f, 0x25, 0x07, 0xd7, 0x46, 0x52, 0xc3, 0x91, 0x54, 0xaa, 0x33, 0x92,
  0x4a, 0x87, 0x63, 0x50, 0x08, 0x94, 0xd4, 0x89, 0xb2, 0x3b, 0xb9, 0xec,
  0x4e, 0x94, 0xdd, 0xd9, 0xd1, 0x4e, 0x56, 0x3c, 0x38, 0xd9, 0x89, 0xa4,
  0x54, 0x42, 0x61, 0xed, 0x64, 0xcd, 0xd4, 0xce, 0x50, 0x6c, 0x30, 0x19,
  0x8f, 0x0c, 0xd6, 0x84, 0x12, 0x89, 0x9a, 0xd5, 0x68, 0xfe, 0x18, 0xaa,
  0x6a, 0xa2, 0xc5, 0xb9, 0xf2, 0x44, 0x22, 0x1a, 0x19, 0x08, 0x71, 0xdf,
  0x2a, 0x33, 0x36, 0x9d, 0x91, 0x3d, 0xe1, 0x81, 0x83, 0x03, 0xd1, 0x70,
  0x4b, 0x28, 0x1a, 0xed, 0x0f, 0x0d, 0xec, 0x4b, 0x35, 0xd1, 0xb4, 0xc9,
  0x72, 0x99, 0x55, 0x03, 0xf1, 0x18, 0x9a, 0x9a, 0xae, 0x69, 0x61, 0x7a,
  0x20, 0x6d, 0x56, 0xed, 0x4d, 0x86, 0x12, 0x43, 0x91, 0x81, 0x54, 0x4d,
  0x4b, 0x28, 0x36, 0x16, 0x42, 0x81, 0xb3, 0xcf, 0xa0, 0x8a, 0x47, 0xe3,
  0xc9, 0xb6, 0x48, 0x34, 0x1d, 0x4e, 0x4e, 0xae, 0xdf, 0x18, 0x4a, 0x27,
  0x23, 0x07, 0x9a, 0x68, 0xc1, 0x7b, 0xea, 0x73, 0x8a, 0x2a, 0x9f, 0x68,
  0xda, 0x15, 0x8a, 0xc4, 0xd2, 0x67, 0xd6, 0xc4, 0xa5, 0xa6, 0x6c, 0xa2,
  0x66, 0x2b, 0x5c, 0xa0, 0x89, 0xa6, 0x67, 0x15, 0xf1, 0x54, 0xcd, 0x9a,
  0xd1, 0x48, 0x74, 0xb0, 0xb2, 0xa7, 0x75, 0x6b, 0x77, 0xfb, 0xe6, 0x4d,
  0x4d, 0x54, 0x92, 0xab, 0x8b, 0x0d, 0x46, 0xc3, 0x4d, 0x34, 0xc5, 0x2c,
  0x6c, 0x5f, 0x13, 0x89, 0x0d, 0x72, 0x9b, 0xc6, 0xcb, 0xe7, 0x91, 0xaa,
  0x69, 0x1d, 0x8c, 0xa4, 0x43, 0xfd, 0x6c, 0x5e, 0x9e, 0xab, 0xe8, 0x0e,
  0x47, 0x95, 0xe7, 0x99, 0x6b, 0x56, 0x9a, 0x44, 0x28, 0xa6, 0x3d, 0x77,
  0x62, 0x2e, 0xe8, 0x62, 0xaa, 0xbc, 0x79, 0x93, 0x68, 0xba, 0x31, 0x4c,
  0xb1, 0xbd, 0xb2, 0x03, 0x5c, 0xc0, 0x69, 0x85, 0x07, 0xf1, 0xc8, 0x16,
  0x3e, 0xde, 0xad, 0xd1, 0x74, 0x24, 0xca, 0x63, 0x77, 0x66, 0xe1, 0x72,
  0x3a, 0x27, 0x2b, 0x1c, 0xc3, 0xea, 0xa9, 0x69, 0x19, 0x8a, 0x27, 0xc3,
  0x71, 0x39, 0x80, 0xe1, 0x64, 0x65, 0x5b, 0x32, 0x34, 0x9c, 0x75, 0xa9,
  0x26, 0x9a, 0xf9, 0x1e, 0xb6, 0xe6, 0xf1, 0x91, 0x5a, 0xac, 0x89, 0xd6,
  0xb1, 0x70, 0x2c, 0x67, 0xfc, 0xa5, 0x62, 0x63, 0x9c, 0x07, 0x47, 0xeb,
  0x16, 0xe4, 0xea, 0x78, 0x05, 0x57, 0x6e, 0x8e, 0xb5, 0xc5, 0x07, 0x46,
  0x53, 0x6a, 0xa5, 0x67, 0xd6, 0x92, 0xb9, 0xf9, 0x59, 0x53, 0xf3, 0x28,
  0x66, 0x85, 0xeb, 0x92, 0xf1, 0xd1, 0x44, 0x13, 0x2d, 0x99, 0xa8, 0x09,
  0x26, 0xc3, 0xe1, 0xcd, 0xfd, 0xa9, 0x70, 0x72, 0x0c, 0x7d, 0xdb, 0x1c,
  0x5b, 0x17, 0x8d, 0xf7, 0x87, 0xa2, 0x9d, 0xa1, 0x83, 0xf1, 0xd1, 0xf4,
  0x78, 0x35, 0x73, 0xde, 0x3b, 0x5f, 0x13, 0x95, 0xe6, 0x1a, 0x9c, 0x07,
  0xf7, 0x88, 0xa3, 0x25, 0xbe, 0x33, 0x89, 0xdb, 0x63, 0xa9, 0x70, 0x3a,
  0x55, 0x19, 0x3c, 0x98, 0xc8, 0x99, 0xd7, 0x09, 0x16, 0xbc, 0xfc, 0x92,
  0xf1, 0x68, 0x94, 0xcb, 0xaf, 0xcd, 0x35, 0x0b, 0x99, 0xc3, 0x4e, 0x4d,
  0x4e, 0x10, 0xda, 0x18, 0x8a, 0x85, 0xf6, 0x72, 0x96, 0xba, 0x7f, 0x3a,
  0x0b, 0xc7, 0xad, 0xf6, 0xd8, 0x9e, 0xf8, 0x84, 0xf1, 0x79, 0x9f, 0x3c,
  0x99, 0x58, 0xd7, 0x44, 0xd5, 0xb9, 0xf9, 0x22, 0xb1, 0xc4, 0x68, 0x7a,
  0x38, 0x9c, 0x1e, 0x8a, 0x0f, 0xd6, 0xac, 0x09, 0xa5, 0x50, 0x38, 0xd2,
  0xe3, 0xd1, 0x77, 0x42, 0xaf, 0xcd, 0xf6, 0xbc, 0x84, 0xe2, 0x49, 0xd5,
  0x9c, 0x73, 0x26, 0x37, 0x9b, 0x50, 0xa4, 0xff, 0x7d, 0x6c, 0x37, 0x4a,
  0x3e, 0x3b, 0x3a, 0x4d, 0x9d, 0x03, 0xf1, 0xe1, 0x9a, 0xe4, 0x70, 0x2a,
  0x5a, 0x73, 0x21, 0xe2, 0x78, 0xcd, 0x84, 0x3d, 0xa3, 0xb2, 0xb2, 0xf5,
  0x00, 0xc2, 0x4e, 0x2c, 0x14, 0xcd, 0x6e, 0x13, 0x9d, 0x72, 0xbb, 0x0a,
  0xfc, 0x5f, 0x32, 0xd7, 0xfe, 0x5f, 0x32, 0xd7, 0x35, 0x51, 0xcd, 0xfb,
  0x66, 0xce, 0xd9, 0x0b, 0x9b, 0x68, 0xe1, 0xfb, 0x67, 0x30, 0x0d, 0xe2,
  0xaa, 0xf7, 0xb5, 0x7e, 0xcf, 0x4d, 0xaf, 0x89, 0xda, 0xde, 0xb7, 0x80,
  0x49, 0xb6, 0xc5, 0xca, 0xdc, 0xf5, 0xd4, 0xf8, 0xff, 0x5b, 0x0e, 0xfb,
  0xe2, 0xfb, 0x65, 0xdd, 0x18, 0x1f, 0x4d, 0x85, 0xd7, 0x87, 0x38, 0xae,
  0xcb, 0xa5, 0xf5, 0x7e, 0xf6, 0x1c, 0x45, 0xa5, 0x0f, 0x05, 0x43, 0xc9,
  0xbd, 0x61, 0x04, 0xa8, 0xb9, 0xef, 0x97, 0xa5, 0x89, 0x2a, 0x3a, 0x07,
  0x43, 0xd1, 0xb1, 0xc8, 0xbe, 0x1a, 0xc4, 0xe9, 0x78, 0x5a, 0x6e, 0xb1,
  0x35, 0xad, 0xb1, 0x81, 0x68, 0x3c, 0x85, 0x70, 0x2d, 0xcf, 0x1b, 0xbc,
  0x37, 0x4e, 0xb4, 0x69, 0xc7, 0x64, 0x24, 0xb5, 0x7e, 0xee, 0x19, 0xf4,
  0x1b, 0xc3, 0xc3, 0xfd, 0xda, 0x20, 0x0c, 0x93, 0xca, 0x33, 0x9a, 0xb0,
  0xa7, 0x77, 0x85, 0x38, 0x4e, 0xc3, 0x8f, 0x60, 0x35, 0xeb, 0x0c, 0x56,
  0xdd, 0x91, 0xbd, 0xb1, 0x50, 0x7a, 0x34, 0x29, 0xf7, 0x2a, 0x3e, 0x1f,
  0xd5, 0x44, 0xe1, 0x38, 0x88, 0xdf, 0xa1, 0x64, 0x77, 0x78, 0x64, 0x34,
  0x1c, 0x1b, 0x08, 0x73, 0xdc, 0x1b, 0xd7, 0xb4, 0x8d, 0xc6, 0xa4, 0x97,
  0x84, 0xa2, 0xed, 0x38, 0x16, 0x24, 0xf7, 0x84, 0xd8, 0xa0, 0xc4, 0x64,
  0xc0, 0x62, 0xb9, 0xb6, 0xbc, 0x26, 0xe1, 0xe6, 0xfe, 0x0b, 0xe5, 0x7e,
  0x6b, 0x96, 0xa9, 0x3d, 0x8b, 0x83, 0xa6, 0x94, 0xc9, 0x8d, 0x67, 0x75,
  0x32, 0x19, 0x3a, 0xc8, 0x93, 0xc8, 0x3b, 0xed, 0xb8, 0xb8, 0x1d, 0x35,
  0x85, 0x10, 0x0f, 0x9a, 0xc8, 0x6d, 0x92, 0x2a, 0xbb, 0xd3, 0x25, 0xcb,
  0xc9, 0x65, 0x9e, 0x59, 0x72, 0x74, 0xaf, 0xdd, 0xb0, 0xab, 0x7d, 0x53,
  0x90, 0x8a, 0x4f, 0x9b, 0x40, 0x72, 0x99, 0x9d, 0x8d, 0x44, 0x0f, 0x19,
  0x3d, 0x38, 0x73, 0xf5, 0xe0, 0x04, 0x66, 0xed, 0xe1, 0x23, 0x9f, 0x8d,
  0x9f, 0x52, 0x82, 0xb3, 0x5a, 0x4f, 0x07, 0xd9, 0x7b, 0x3a, 0xda, 0xdb,
  0xda, 0x70, 0x22, 0xeb, 0xe9, 0x90, 0xda, 0x0e, 0xa5, 0xc5, 0x41, 0x10,
  0x8f, 0x4e, 0x16, 0xf3, 0xc1, 0xad, 0xa7, 0xa3, 0x17, 0xd6, 0xcc, 0x74,
  0x72, 0x41, 0x9d, 0xd2, 0xb4, 0x53, 0x99, 0xf2, 0x39, 0xaf, 0x07, 0x46,
  0x10, 0xb0, 0xdc, 0x21, 0x89, 0xac, 0xaf, 0x53, 0x66, 0xed, 0xec, 0x65,
  0xb6, 0xb7, 0x43, 0x3e, 0x3b, 0xe5, 0x93, 0x0b, 0xeb, 0x45, 0xd5, 0xbd,
  0xd2, 0x50, 0xf4, 0x92, 0xa5, 0x97, 0x33, 0xe0, 0xd1, 0xc9, 0x2c, 0x5a,
  0x06, 0x73, 0x5b, 0x6f, 0x07, 0xa7, 0xad, 0x20, 0x2c, 0x60, 0x0d, 0x2a,
  0xb7, 0xf7, 0x76, 0x4a, 0xb1, 0x8d, 0x29, 0xcb, 0x51, 0x56, 0x1f, 0x4e,
  0xb7, 0x7d, 0xed, 0xe4, 0x54, 0x31, 0xbd, 0x32, 0x10, 0x08, 0x64, 0xf9,
  0x5a, 0xf0, 0x05, 0xe3, 0xbc, 0x29, 0x91, 0xa3, 0xa9, 0x33, 0x27, 0x16,
  0x99, 0x13, 0x8b, 0xcd, 0x89, 0x7a, 0x73, 0x62, 0x89, 0x39, 0xb1, 0xd4,
  0x9c, 0x68, 0x30, 0x27, 0x1a, 0x4d, 0xad, 0x31, 0x57, 0x53, 0x67, 0x6e,
  0xe6, 0x22, 0x13, 0xbf, 0xd8, 0xc4, 0xd7, 0x9b, 0xf8, 0x25, 0x26, 0x7e,
  0xa9, 0x89, 0x6f, 0x30, 0xf1, 0x8d, 0xe3, 0x15, 0xb4, 0x45, 0x43, 0x7b,
  0x53, 0x54, 0x98, 0xb3, 0xcf, 0xd1, 0x94, 0xd0, 0x19, 0xf6, 0x53, 0xce,
  0xc1, 0xde, 0xdf, 0x19, 0xea, 0x0f, 0x47, 0xc9, 0x12, 0x1a, 0x1c, 0xa4,
  0x69, 0x78, 0x9c, 0xf9, 0xc0, 0x40, 0xee, 0xd0, 0x1e, 0x38, 0x2e, 0xbb,
  0x9d, 0x0a, 0xc7, 0x83, 0xe4, 0xe1, 0xd3, 0xd2, 0x9a, 0xd1, 0x74, 0x3a,
  0x1e, 0xeb, 0x4a, 0xa2, 0x74, 0x29, 0x0a, 0xef, 0xc1, 0x61, 0xc9, 0x6c,
  0x65, 0xef, 0x8f, 0xc3, 0x62, 0x98, 0xec, 0x03, 0x21, 0x84, 0xef, 0x41,
  0x72, 0x2b, 0x6a, 0xba, 0xb8, 0x14, 0x0e, 0xe4, 0xdc, 0x75, 0x6c, 0x38,
  0xde, 0x87, 0x92, 0x54, 0xcc, 0x81, 0x25, 0x6c, 0x32, 0x2b, 0x93, 0x02,
  0xd3, 0xc6, 0xa7, 0xcf, 0xf2, 0x54, 0x30, 0xc0, 0xf1, 0x9a, 0x0f, 0xc7,
  0xab, 0xd3, 0x54, 0x94, 0x4d, 0xb4, 0xc4, 0x47, 0x63, 0x69, 0x14, 0x0e,
  0x2b, 0x1c, 0xa9, 0x53, 0x52, 0x46, 0x53, 0xf4, 0x45, 0x20, 0xb5, 0x46,
  0x36, 0x54, 0x35, 0x92, 0x66, 0x0c, 0x24, 0xc3, 0xa1, 0xf4, 0xc4, 0x4d,
  0x80, 0xb7, 0x6c, 0x72, 0x0c, 0xc6, 0xe5, 0xf9, 0x90, 0xf2, 0xc2, 0xfa,
  0x28, 0x0c, 0x2e, 0x36, 0x98, 0x3a, 0x2f, 0x92, 0x1e, 0x22, 0xdf, 0x1e,
  0x9c, 0x6e, 0xce, 0x98, 0x2f, 0xb5, 0xe6, 0x20, 0x0f, 0x03, 0xe5, 0xb3,
  0x85, 0x3c, 0xe8, 0x91, 0x6b, 0xcf, 0xf8, 0x79, 0x6f, 0x90, 0x66, 0x60,
  0xd9, 0xe6, 0xe4, 0x94, 0x46, 0x1c, 0x6a, 0xdb, 0x07, 0x69, 0xe6, 0xe9,
  0xca, 0x9c, 0x8b, 0x58, 0xbe, 0xd4, 0xca, 0x51, 0x29, 0xca, 0xb2, 0xed,
  0x38, 0xbe, 0x1f, 0xa0, 0xe2, 0x6c, 0x7a, 0x63, 0x28, 0xb5, 0x0f, 0xd5,
  0x94, 0xb2, 0x60, 0xfc, 0x52, 0x94, 0x19, 0x34, 0x37, 0xc4, 0x2d, 0xa1,
  0x64, 0x38, 0xdd, 0x85, 0xf0, 0x2d, 0x4b, 0x9a, 0xc2, 0x12, 0x84, 0x4a,
  0x59, 0x4e, 0x5b, 0x3c, 0xa9, 0x06, 0xac, 0x50, 0x4b, 0xe1, 0x2a, 0x88,
  0xbb, 0x54, 0xc2, 0x49, 0xde, 0x1a, 0x38, 0xe6, 0xf3, 0x89, 0xbd, 0x35,
  0xa6, 0xaa, 0xc8, 0x11, 0x76, 0xa7, 0x43, 0xc9, 0x34, 0x39, 0xa5, 0x58,
  0x55, 0xe7, 0x02, 0xbf, 0x36, 0x3c, 0x10, 0x97, 0x5b, 0x09, 0x15, 0x20,
  0x95, 0xb9, 0x57, 0x48, 0x95, 0x3c, 0x25, 0x07, 0x23, 0x18, 0xe4, 0x69,
  0x48, 0xc9, 0x81, 0x08, 0x0f, 0x9e, 0x1e, 0xe2, 0x7c, 0x93, 0xaa, 0x64,
  0x53, 0xf5, 0xb8, 0xac, 0x0f, 0x47, 0xf6, 0x0e, 0xa5, 0x65, 0x39, 0xeb,
  0xc1, 0x45, 0x39, 0x15, 0x1e, 0xdc, 0x1a, 0xde, 0x8b, 0x3e, 0xae, 0xc1,
  0x13, 0x8e, 0x74, 0x26, 0x15, 0xf7, 0x83, 0x3b, 0x27, 0x4b, 0x35, 0xcf,
  0x44, 0x69, 0x46, 0x98, 0x73, 0xda, 0xa2, 0xf9, 0x19, 0x31, 0x9f, 0x79,
  0x31, 0x5a, 0x7c, 0x88, 0xe8, 0x89, 0x24, 0xd3, 0xa3, 0xa1, 0x68, 0x66,
  0x1b, 0x67, 0x8d, 0xec, 0x2a, 0xce, 0xbe, 0xe9, 0x10, 0x36, 0x1f, 0x39,
  0x39, 0x39, 0x5a, 0xae, 0xb1, 0x33, 0xae, 0x66, 0x66, 0x73, 0xac, 0x1b,
  0x6e, 0x18, 0x8e, 0xc9, 0x01, 0x41, 0x65, 0x21, 0x8c, 0x62, 0x3a, 0x2c,
  0x27, 0x60, 0x13, 0x0c, 0xc6, 0xc2, 0x72, 0xe8, 0x8a, 0xc7, 0xbb, 0xab,
  0x1c, 0xdc, 0x35, 0x2e, 0x40, 0x6b, 0x1d, 0x48, 0x6d, 0x0d, 0xed, 0xdf,
  0x9e, 0x61, 0x76, 0xc8, 0x06, 0x6c, 0x8d, 0xc7, 0xd3, 0xd9, 0xdc, 0xd9,
  0x7b, 0x1b, 0x77, 0xd9, 0x63, 0x16, 0xa8, 0x69, 0x63, 0xcf, 0xe8, 0x3e,
  0x88, 0x55, 0x3f, 0xdc, 0x8d, 0xcd, 0x24, 0x82, 0x66, 0x97, 0x66, 0x25,
  0xdb, 0x22, 0x3d, 0x91, 0x6c, 0x50, 0x61, 0xd7, 0x53, 0x13, 0xb1, 0x55,
  0xae, 0x22, 0xce, 0x18, 0xc4, 0x5e, 0x1c, 0xdd, 0x34, 0x3a, 0xcc, 0x2e,
  0xa3, 0xbc, 0x65, 0x1b, 0xdf, 0x2a, 0xa3, 0x91, 0x18, 0x06, 0x9a, 0xad,
  0x52, 0x32, 0xdb, 0xb6, 0x58, 0x84, 0xd7, 0x29, 0x5b, 0x49, 0xa3, 0xd3,
  0x6f, 0x1f, 0xb2, 0xd7, 0xa6, 0xaa, 0x78, 0x36, 0xcf, 0x7c, 0x8f, 0x90,
  0xc5, 0x29, 0x55, 0x30, 0xbe, 0x0f, 0xa3, 0x37, 0x33, 0x9b, 0x96, 0xf9,
  0xa3, 0x61, 0x9c, 0xa6, 0x12, 0xd1, 0xd0, 0x41, 0xb5, 0x86, 0xad, 0xd0,
  0x6e, 0x97, 0xcf, 0x1d, 0x64, 0x1f, 0x92, 0xbb, 0x2a, 0x95, 0x2b, 0x9a,
  0xb3, 0xdc, 0xd6, 0xc7, 0xb9, 0x15, 0xc5, 0x5a, 0x93, 0x48, 0x74, 0x85,
  0xd8, 0xed, 0xc8, 0x9d, 0x15, 0x6c, 0x0d, 0xa7, 0x46, 0x87, 0xc7, 0x25,
  0x6b, 0xb2, 0xa1, 0x90, 0x0a, 0x95, 0x64, 0xad, 0x8e, 0x1a, 0x3a, 0x89,
  0x69, 0x5f, 0x1b, 0xdf, 0x1f, 0xa3, 0x82, 0x6c, 0x72, 0x5b, 0x82, 0xa6,
  0x64, 0x13, 0xd2, 0x25, 0xd6, 0x47, 0x06, 0x07, 0xd1, 0x03, 0x5d, 0xab,
  0xdc, 0xf8, 0x65, 0x9e, 0x1c, 0x41, 0x32, 0xb4, 0x37, 0x53, 0xa6, 0x14,
  0xa0, 0x98, 0x32, 0x9d, 0x1c, 0x8d, 0xa6, 0x23, 0xda, 0x15, 0xe4, 0x82,
  0xca, 0x54, 0x26, 0x5f, 0x29, 0x50, 0x89, 0x4e, 0xe0, 0x9c, 0x13, 0x4f,
  0x0e, 0xeb, 0xf0, 0x31, 0x43, 0x09, 0xbb, 0xb1, 0x34, 0x63, 0x83, 0xa1,
  0xe4, 0xc1, 0x9c, 0xec, 0x8e, 0xa1, 0x50, 0x6a, 0x13, 0xaf, 0x5e, 0xeb,
  0x10, 0xc2, 0x0e, 0xb9, 0xf8, 0x99, 0x69, 0x2b, 0x2a, 0x45, 0xaa, 0x3b,
  0xbe, 0x47, 0xaf, 0x98, 0x64, 0x7c, 0x58, 0x8d, 0x3a, 0xe5, 0x0d, 0xa1,
  0x88, 0xa0, 0xca, 0x16, 0x4f, 0x21, 0x0c, 0x60, 0x59, 0x6f, 0x4e, 0x70,
  0x6d, 0x29, 0x2a, 0xe6, 0xf7, 0x5d, 0x91, 0x50, 0xb4, 0x25, 0x94, 0x48,
  0x6d, 0x84, 0x03, 0x50, 0xa1, 0x16, 0xc0, 0x07, 0xd9, 0x1d, 0x8b, 0xc7,
  0x93, 0xca, 0x19, 0xf3, 0x23, 0x99, 0x35, 0x46, 0x2e, 0xc9, 0xee, 0x52,
  0x17, 0x20, 0xf2, 0x20, 0xa4, 0x87, 0x93, 0xb2, 0x9e, 0xd5, 0x2a, 0x90,
  0x51, 0x1e, 0xea, 0xed, 0x09, 0x45, 0x47, 0x11, 0x9f, 0x23, 0xa9, 0xcd,
  0x89, 0x10, 0x4e, 0x7c, 0x30, 0x4b, 0x65, 0x63, 0x85, 0x7c, 0x89, 0x84,
  0x08, 0x03, 0x51, 0x7c, 0x74, 0x60, 0xa8, 0xf5, 0x40, 0x22, 0x1a, 0x4f,
  0x86, 0xd4, 0x4a, 0xe0, 0x48, 0x34, 0x88, 0xda, 0x52, 0xda, 0x69, 0x50,
  0x84, 0x3e, 0xa6, 0x51, 0xd9, 0xbe, 0x49, 0xde, 0x7a, 0x15, 0x66, 0x14,
  0xdd, 0x43, 0x3c, 0x4b, 0xb6, 0xa8, 0xdc, 0x47, 0xed, 0xd1, 0x70, 0x6c,
  0x2f, 0x76, 0x06, 0x6b, 0x8c, 0x67, 0xdf, 0xc6, 0xcf, 0x14, 0x12, 0x32,
  0x08, 0xc6, 0xcc, 0x41, 0xdc, 0x1e, 0xef, 0xe7, 0x8d, 0x89, 0xbc, 0xf1,
  0x3d, 0x7b, 0xe0, 0xd3, 0x6b, 0x0e, 0xb6, 0x64, 0x76, 0xae, 0x14, 0x79,
  0xe2, 0xb1, 0xcc, 0x2b, 0xaf, 0x16, 0xb9, 0x35, 0x21, 0x38, 0x8d, 0x8b,
  0xd6, 0x86, 0x53, 0xf0, 0xfe, 0x83, 0xec, 0x7d, 0xe3, 0x42, 0xed, 0xa1,
  0xa6, 0x9c, 0x19, 0x17, 0x9d, 0x31, 0x2e, 0xea, 0x0e, 0x8d, 0x85, 0x33,
  0xd1, 0x48, 0x85, 0x17, 0x93, 0xbd, 0x1c, 0xf1, 0xdc, 0x22, 0xba, 0xd3,
  0xf1, 0x44, 0x02, 0xa2, 0x32, 0x6c, 0x1c, 0xb2, 0x1d, 0xa7, 0xdd, 0x51,
  0xd1, 0x89, 0x18, 0x3c, 0x72, 0x3f, 0x15, 0xc6, 0xcd, 0x2f, 0x33, 0xa8,
  0x28, 0x9e, 0x73, 0x88, 0x20, 0x57, 0x3c, 0x26, 0x57, 0x94, 0xf2, 0xab,
  0xfc, 0x78, 0x2c, 0xb3, 0x1c, 0x0a, 0x25, 0x2b, 0x3d, 0x37, 0x81, 0x51,
  0x77, 0xc8, 0x24, 0x5c, 0x3a, 0x8f, 0x8f, 0x25, 0x32, 0x2b, 0x2c, 0xba,
  0x23, 0x17, 0x85, 0x33, 0xbb, 0x66, 0x01, 0x92, 0xd8, 0x61, 0x56, 0x63,
  0xa5, 0x0c, 0x4a, 0x1d, 0x12, 0x19, 0x9d, 0x4e, 0x6e, 0x0d, 0x0f, 0xa3,
  0x2e, 0x99, 0x34, 0x1f, 0x44, 0xd0, 0x06, 0x35, 0xef, 0xb2, 0x0d, 0xf6,
  0xb8, 0x72, 0x10, 0x5b, 0x42, 0x2e, 0x8e, 0xc2, 0x44, 0xce, 0xb2, 0x98,
  0x95, 0x88, 0x27, 0x46, 0xa3, 0x93, 0x1e, 0x09, 0x3c, 0xd8, 0xea, 0xd2,
  0x39, 0x2f, 0x8d, 0xc8, 0x91, 0x54, 0x2f, 0x26, 0xa9, 0x22, 0x89, 0xfd,
  0x04, 0x1e, 0x92, 0x9c, 0xfc, 0x9d, 0x25, 0xcd, 0x4c, 0xca, 0x26, 0x4e,
  0x72, 0xd2, 0x72, 0x2a, 0x2d, 0x77, 0x85, 0x5c, 0x38, 0x58, 0xf1, 0xb4,
  0xc8, 0x71, 0x27, 0x0b, 0xfc, 0x84, 0x8a, 0x52, 0xbc, 0xad, 0x66, 0x5f,
  0x22, 0x92, 0x2b, 0xa5, 0xb7, 0x45, 0xb9, 0x9b, 0x96, 0x99, 0x53, 0xed,
  0xaa, 0xc7, 0x72, 0xa5, 0x4d, 0x49, 0x9d, 0x61, 0xd7, 0xa3, 0x12, 0x48,
  0xdb, 0x87, 0xf9, 0x98, 0xc5, 0xbe, 0x92, 0x52, 0xd5, 0x70, 0x89, 0x68,
  0x13, 0x4e, 0x7b, 0xbc, 0xee, 0x4a, 0x53, 0xbc, 0x01, 0x8d, 0x45, 0xf6,
  0xca, 0xa5, 0xb2, 0x26, 0x94, 0x94, 0x95, 0x53, 0x39, 0xc4, 0x67, 0x7c,
  0x83, 0x25, 0xb3, 0x67, 0xf7, 0x14, 0x72, 0x70, 0x8a, 0xbb, 0xc2, 0x2d,
  0x53, 0xbb, 0x08, 0xca, 0x48, 0x21, 0x84, 0xe2, 0x94, 0x27, 0x77, 0xc5,
  0xd2, 0x1c, 0xc5, 0x9a, 0xf0, 0x10, 0x2a, 0x43, 0x05, 0xe3, 0xe2, 0x9c,
  0x5d, 0x67, 0xc6, 0x19, 0xc5, 0x7c, 0xfc, 0x08, 0xa5, 0x65, 0x1d, 0xc1,
  0x30, 0x4e, 0x22, 0x49, 0xc4, 0xb2, 0xcc, 0xce, 0x83, 0x43, 0x09, 0x15,
  0xa4, 0xd4, 0x26, 0xb3, 0x49, 0x86, 0xe4, 0x54, 0xce, 0xe6, 0xe2, 0xcc,
  0x24, 0x31, 0x7c, 0x3c, 0xb8, 0xe7, 0x45, 0xa2, 0xd1, 0x4d, 0xf1, 0xb4,
  0xf4, 0x6b, 0x6b, 0x0a, 0x6b, 0x1b, 0x3d, 0xc2, 0x33, 0x1b, 0xf9, 0x0a,
  0x39, 0x95, 0x8d, 0x7c, 0xc8, 0xc2, 0x13, 0xa4, 0x7a, 0xcf, 0x55, 0x15,
  0xa6, 0xb0, 0x68, 0xc6, 0x93, 0x05, 0xa9, 0xd1, 0xfe, 0xcc, 0xed, 0x93,
  0xf2, 0x91, 0x48, 0xc9, 0xab, 0x22, 0x6a, 0xcd, 0x76, 0x99, 0xec, 0x69,
  0x75, 0xc2, 0x99, 0x93, 0xce, 0x3d, 0xd7, 0xac, 0x3b, 0xfd, 0x8c, 0x76,
  0xd6, 0x19, 0x0c, 0x26, 0x1c, 0xd9, 0xaa, 0x26, 0x1a, 0x4d, 0x72, 0x12,
  0x9a, 0xff, 0x4f, 0x58, 0x72, 0x58, 0x9e, 0x3d, 0xd1, 0x2e, 0xe7, 0x18,
  0x33, 0x6b, 0xa2, 0xde, 0x7c, 0x30, 0x38, 0x43, 0xb7, 0x72, 0xcf, 0x09,
  0xbe, 0xd3, 0x0c, 0xda, 0x27, 0xc4, 0xf6, 0x09, 0x16, 0x13, 0xc2, 0xfa,
  0xe9, 0x43, 0xd3, 0x7d, 0x26, 0x77, 0x3f, 0xbd, 0xc3, 0xdd, 0x93, 0xb8,
  0x8b, 0x3d, 0x3d, 0x14, 0xc1, 0x85, 0x52, 0xd3, 0x5a, 0xca, 0x4b, 0xc7,
  0xd5, 0x0d, 0x9f, 0x2c, 0x98, 0x5c, 0x9a, 0x3b, 0x9a, 0x18, 0x44, 0x70,
  0xc8, 0x1c, 0x61, 0xb3, 0xce, 0xce, 0xbb, 0xa0, 0x3e, 0xac, 0x2e, 0x50,
  0x26, 0x2a, 0xa5, 0x0f, 0xc7, 0x6c, 0xa2, 0x0e, 0x41, 0x6c, 0x98, 0x3d,
  0x00, 0xcf, 0x36, 0x9b, 0x9e, 0x41, 0x3f, 0xd7, 0xac, 0xcf, 0xa9, 0x2b,
  0x6b, 0x62, 0x1b, 0x93, 0xfb, 0x9e, 0x43, 0x92, 0xcd, 0x7b, 0xc8, 0x3a,
  0x26, 0x4f, 0x7b, 0xfc, 0x34, 0x07, 0x4f, 0xf7, 0xd8, 0xe9, 0xe7, 0xac,
  0x9b, 0xc5, 0x65, 0x97, 0xad, 0x6d, 0xb8, 0xb8, 0x82, 0xe3, 0x12, 0x2e,
  0x35, 0x15, 0xcb, 0x2a, 0xe0, 0x49, 0x15, 0x0b, 0x2b, 0x06, 0xd0, 0xe2,
  0x48, 0x54, 0xae, 0x78, 0xff, 0x30, 0xc2, 0x07, 0x14, 0x49, 0xd4, 0x1c,
  0x4a, 0x85, 0xa1, 0xc4, 0xb1, 0xc0, 0x8f, 0xab, 0x1a, 0x22, 0xd9, 0xe8,
  0x70, 0xaa, 0x62, 0xd9, 0x9e, 0x50, 0x34, 0x15, 0x5e, 0x58, 0x31, 0x1c,
  0x89, 0xf9, 0x43, 0x89, 0x48, 0xc5, 0xb2, 0xba, 0xc5, 0x0b, 0x2b, 0x52,
  0x43, 0x21, 0x7f, 0x2d, 0x32, 0x85, 0x96, 0x86, 0x06, 0x6b, 0x1b, 0x42,
  0x4b, 0x03, 0x8b, 0x97, 0x04, 0xfa, 0x97, 0x36, 0x36, 0x0e, 0x06, 0x16,
  0x37, 0xd4, 0x85, 0x17, 0x37, 0x2e, 0x1d, 0xa8, 0x0d, 0x34, 0x86, 0x96,
  0xd6, 0xf7, 0xef, 0x59, 0xba, 0xa7, 0xb1, 0x76, 0x90, 0x4b, 0x45, 0x73,
  0x52, 0xa8, 0x0e, 0x99, 0x1a, 0xaa, 0x6b, 0x03, 0xd5, 0x8d, 0xfe, 0xc1,
  0xf0, 0x58, 0xc5, 0xa5, 0x64, 0x2c, 0x11, 0xef, 0x18, 0xe5, 0xf5, 0xc6,
  0x52, 0xe3, 0x7e, 0x51, 0xe9, 0xb4, 0xdf, 0x6a, 0x94, 0x45, 0xc5, 0x72,
  0x32, 0x96, 0x41, 0x3a, 0x33, 0xaf, 0xcc, 0x51, 0xd6, 0x50, 0x96, 0x5f,
  0xb6, 0xaf, 0x6c, 0x55, 0x59, 0x18, 0xbf, 0x2e, 0x69, 0x65, 0x9d, 0x0e,
  0xa3, 0xa2, 0x71, 0xd6, 0x6d, 0x34, 0x82, 0x9d, 0x69, 0x54, 0xba, 0xdd,
  0x56, 0xba, 0xcd, 0x98, 0x69, 0xcc, 0x9e, 0xad, 0xb2, 0xdb, 0x91, 0x7d,
  0x6f, 0x59, 0x29, 0xb2, 0x6f, 0x2c, 0x2b, 0x50, 0xf6, 0x5e, 0xd8, 0xcf,
  0x56, 0xf6, 0x02, 0xf6, 0xb0, 0x16, 0xb3, 0x55, 0x0b, 0xea, 0x94, 0x81,
  0x01, 0x83, 0xf8, 0xb8, 0xed, 0x1c, 0xa3, 0x81, 0x4b, 0x12, 0xe5, 0xb5,
  0xe3, 0x45, 0x66, 0x5a, 0x53, 0xa8, 0xcc, 0xf2, 0x61, 0x16, 0xcb, 0x68,
  0xf3, 0x4c, 0x5a, 0x99, 0xd3, 0x5e, 0x5e, 0x57, 0x1e, 0x28, 0x5f, 0x54,
  0xbe, 0xb8, 0xbc, 0xa6, 0x9c, 0xbf, 0xc3, 0x29, 0x06, 0x2f, 0xe7, 0x8f,
  0xba, 0x85, 0x58, 0x7d, 0xf9, 0x2d, 0xd6, 0x37, 0x16, 0xae, 0xf1, 0xf0,
  0x17, 0xf7, 0x85, 0x68, 0x41, 0xea, 0x16, 0xff, 0x5a, 0xcf, 0x03, 0x32,
  0xd5, 0x8a, 0xd4, 0x93, 0xfe, 0x36, 0xcf, 0x2b, 0x7e, 0xb2, 0xda, 0xed,
  0x05, 0x86, 0xf0, 0xf2, 0xef, 0xba, 0xcb, 0x0f, 0x59, 0xdf, 0xaa, 0xb6,
  0x38, 0x0f, 0x55, 0xdb, 0x9c, 0x27, 0xea, 0x84, 0xf3, 0x15, 0xe0, 0xe8,
  0x22, 0xe1, 0xbc, 0x7b, 0xd1, 0x7a, 0x71, 0x4b, 0x8d, 0x10, 0xa7, 0x6a,
  0x0c, 0xf1, 0x14, 0xe8, 0x5b, 0xc0, 0xb5, 0x01, 0xa4, 0x03, 0x64, 0x15,
  0x46, 0xb1, 0x21, 0xe4, 0x6f, 0xf7, 0xa1, 0x43, 0xd6, 0x43, 0xf5, 0x41,
  0x71, 0x4b, 0x3d, 0x2c, 0xf8, 0xef, 0x7e, 0xad, 0x25, 0xc7, 0x7d, 0xc2,
  0x7b, 0x1e, 0x0a, 0x7d, 0xb9, 0x61, 0xbb, 0x78, 0x15, 0xe2, 0xc7, 0x1b,
  0x84, 0xb8, 0x7a, 0xa9, 0x10, 0x87, 0x1a, 0xa0, 0x16, 0xa5, 0x86, 0x38,
  0xee, 0xdb, 0x89, 0x5c, 0x87, 0x1b, 0xcf, 0x17, 0x77, 0x37, 0x92, 0xc5,
  0x4e, 0x65, 0x9c, 0x43, 0x78, 0x2f, 0x40, 0x9e, 0xbf, 0x2d, 0x13, 0x47,
  0x7d, 0x27, 0x9b, 0xf0, 0x78, 0x94, 0x1f, 0x2f, 0x2f, 0x13, 0xc6, 0x73,
  0x4d, 0xc2, 0x38, 0xbc, 0x1c, 0xcd, 0x2f, 0x98, 0xee, 0x0d, 0xc3, 0xe4,
  0xe4, 0xca, 0x3d, 0xe2, 0x89, 0xe5, 0x42, 0xbc, 0x0a, 0x5c, 0xbd, 0x42,
  0x88, 0x93, 0xc0, 0x13, 0xc0, 0xd5, 0x2b, 0x21, 0x03, 0x7d, 0x1c, 0xf4,
  0x24, 0x74, 0x2f, 0x83, 0x1e, 0x5a, 0x45, 0x8e, 0xa5, 0x73, 0x67, 0x78,
  0x65, 0x5b, 0xbd, 0xea, 0x77, 0xe4, 0x2a, 0xdf, 0x8b, 0x1d, 0xe2, 0x2a,
  0xdf, 0x3b, 0xfc, 0x38, 0xbe, 0x41, 0xa0, 0xc8, 0xbb, 0x37, 0xa0, 0xae,
  0xa3, 0xab, 0xf1, 0x78, 0x71, 0x1d, 0x1e, 0xaf, 0x6e, 0xc4, 0xe3, 0xf1,
  0x0e, 0x3c, 0x0e, 0x6f, 0xc2, 0xe3, 0xc4, 0x2a, 0x3c, 0x6e, 0x67, 0xed,
  0x5b, 0xed, 0x78, 0x1c, 0x67, 0xc5, 0xdf, 0xd8, 0xee, 0x61, 0x96, 0x9d,
  0x60, 0x93, 0x93, 0x2c, 0x3b, 0xc5, 0xdc, 0x0d, 0xeb, 0x99, 0xe3, 0xc7,
  0x93, 0xfc, 0x78, 0x75, 0xbd, 0xfd, 0x0a, 0x83, 0x04, 0x60, 0x31, 0x4e,
  0xae, 0x63, 0x6a, 0x30, 0x9c, 0x47, 0xdb, 0x99, 0x3a, 0x8e, 0x29, 0xdd,
  0xa4, 0x38, 0x36, 0x0e, 0x43, 0xcb, 0xa6, 0x02, 0x05, 0xc7, 0x72, 0x75,
  0xef, 0x09, 0xd8, 0x1f, 0xc1, 0x08, 0x6d, 0x12, 0xe2, 0x1d, 0xe0, 0xda,
  0xcd, 0x42, 0x3c, 0xb7, 0x1a, 0xa3, 0xb4, 0xd9, 0x22, 0x1e, 0x58, 0x65,
  0xa7, 0xe7, 0x9a, 0x4b, 0xe9, 0x50, 0x97, 0x85, 0x6e, 0xd8, 0x22, 0xc4,
  0x03, 0x5b, 0x85, 0x78, 0x03, 0xba, 0xa3, 0x6b, 0x30, 0x97, 0xe0, 0x8f,
  0x76, 0x0b, 0x71, 0x02, 0x78, 0x1c, 0x78, 0x0b, 0x38, 0x1a, 0x44, 0x1a,
  0x78, 0x72, 0x95, 0x10, 0xf7, 0x83, 0xbe, 0x08, 0x9c, 0x84, 0xed, 0xa1,
  0x16, 0x94, 0x0d, 0x1c, 0x6d, 0x15, 0xd6, 0xe3, 0xdb, 0x84, 0xf5, 0xf6,
  0x6d, 0x42, 0x3c, 0xdc, 0x6a, 0x17, 0x4f, 0x81, 0xbe, 0x75, 0x9e, 0x21,
  0x8e, 0x6e, 0x37, 0xc4, 0xc9, 0xed, 0xf2, 0xb3, 0xf7, 0xe1, 0x8d, 0x44,
  0x69, 0xe0, 0xd0, 0x46, 0xf5, 0xf9, 0xfd, 0x95, 0x1b, 0xd5, 0xe7, 0xf0,
  0x2c, 0xbf, 0xc9, 0xc4, 0xdf, 0xa1, 0xf5, 0xf7, 0x6b, 0xfa, 0x4d, 0x93,
  0xee, 0x69, 0x2d, 0x7b, 0x51, 0xcb, 0x5e, 0x07, 0xfd, 0x9f, 0x8d, 0x94,
  0x2d, 0x5f, 0x6c, 0x22, 0x72, 0x6d, 0x52, 0x36, 0xa5, 0x9b, 0xc6, 0xf3,
  0x55, 0x69, 0xd9, 0x22, 0x4d, 0xdb, 0xf8, 0xef, 0x74, 0xb7, 0x50, 0xce,
  0x4f, 0xb9, 0x4e, 0x67, 0xbe, 0x21, 0xcd, 0x7f, 0x39, 0xe8, 0x86, 0xac,
  0xf2, 0x34, 0xbb, 0x66, 0x9d, 0xce, 0x7c, 0xbb, 0x8b, 0xff, 0x6f, 0x55,
  0x60, 0x8b, 0xfa, 0xbf, 0x55, 0x0d, 0x5b, 0xf8, 0x2f, 0xa5, 0x72, 0xcb,
  0xe1, 0xff, 0x61, 0xd5, 0x09, 0xd9, 0xee, 0xd3, 0xe4, 0x17, 0xe8, 0x7c,
  0x07, 0x4e, 0x93, 0xf3, 0xff, 0x28, 0x4a, 0x40, 0x76, 0xf5, 0x69, 0x72,
  0xfe, 0xfb, 0xff, 0xc3, 0x5b, 0xc6, 0xff, 0x1f, 0x94, 0x30, 0xd1, 0xcc,
  0xff, 0x89, 0xe4, 0x36, 0x65, 0xfe, 0x57, 0x24, 0x8f, 0x49, 0xe6, 0xff,
  0x45, 0xf2, 0xf7, 0x19, 0xf8, 0x2f, 0xea, 0xf8, 0x7f, 0x46, 0xf2, 0x77,
  0x1d, 0x32, 0xff, 0x37, 0x92, 0xbf, 0xfb, 0x91, 0xf9, 0xdf, 0x91, 0xc2,
  0xa7, 0xfe, 0x87, 0x16, 0xff, 0xff, 0x48, 0x8b, 0x4f, 0x95, 0xc3, 0x7f,
  0xdf, 0x2b, 0xdc, 0xea, 0xbb, 0xa1, 0xfc, 0x77, 0xd4, 0x86, 0x4f, 0xd5,
  0xc5, 0xff, 0x5f, 0xd2, 0xea, 0x53, 0xdf, 0x9b, 0xe5, 0xf1, 0x25, 0x9f,
  0x2a, 0x87, 0xff, 0x7e, 0xdb, 0xe2, 0x56, 0xdf, 0x75, 0xe3, 0xf1, 0xb5,
  0xfb, 0xd4, 0xf7, 0x70, 0xf8, 0x6f, 0xbb, 0xb9, 0xe1, 0xdc, 0x56, 0xfe,
  0xbf, 0x96, 0xff, 0x0f, 0xed, 0x4e, 0x37, 0xdd, 0x10, 0x53, 0x00, 0x00
};

//==============================================================================
#if JUCE_PUSH_NOTIFICATIONS && JUCE_MODULE_AVAILABLE_juce_gui_extra
 bool juce_handleNotificationIntent (void*);
 void juce_firebaseDeviceNotificationsTokenRefreshed (void*);
 void juce_firebaseRemoteNotificationReceived (void*);
 void juce_firebaseRemoteMessagesDeleted();
 void juce_firebaseRemoteMessageSent (void*);
 void juce_firebaseRemoteMessageSendError (void*, void*);
#endif

#if JUCE_IN_APP_PURCHASES && JUCE_MODULE_AVAILABLE_juce_product_unlocking
 void juce_handleOnResume();
#else
 static void juce_handleOnResume() {}
#endif

//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 METHOD (create, "<init>", "(II)V") \
 FIELD (width, "width", "I") \
 FIELD (height, "height", "I") \

DECLARE_JNI_CLASS (AndroidLayoutParams, "android/view/ViewGroup$LayoutParams")
#undef JNI_CLASS_MEMBERS

#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 METHOD (addView,          "addView",             "(Landroid/view/View;Landroid/view/ViewGroup$LayoutParams;)V") \
 METHOD (removeView,       "removeView",          "(Landroid/view/View;)V") \
 METHOD (updateViewLayout, "updateViewLayout",    "(Landroid/view/View;Landroid/view/ViewGroup$LayoutParams;)V")

DECLARE_JNI_CLASS (AndroidViewManager, "android/view/ViewManager")
#undef JNI_CLASS_MEMBERS

#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 METHOD (create,             "<init>",             "(IIIIIII)V") \
 METHOD (createDefault,      "<init>",             "()V") \
 FIELD  (gravity,            "gravity",            "I") \
 FIELD  (systemUiVisibility, "systemUiVisibility", "I") \
 FIELD  (windowAnimations,   "windowAnimations",   "I") \
 FIELD  (flags,              "flags",              "I") \
 FIELD  (softInputMode,      "softInputMode",      "I") \
 FIELD  (format,             "format",             "I") \
 FIELD  (type,               "type",               "I") \
 FIELD  (x,                  "x",                  "I") \
 FIELD  (y,                  "y",                  "I") \

DECLARE_JNI_CLASS (AndroidWindowManagerLayoutParams, "android/view/WindowManager$LayoutParams")
#undef JNI_CLASS_MEMBERS

#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 FIELD  (layoutInDisplayCutoutMode, "layoutInDisplayCutoutMode", "I")

DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidWindowManagerLayoutParams28, "android/view/WindowManager$LayoutParams", 28)
#undef JNI_CLASS_MEMBERS

#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 METHOD (setFitInsetsSides,              "setFitInsetsSides",              "(I)V") \
 METHOD (setFitInsetsIgnoringVisibility, "setFitInsetsIgnoringVisibility", "(Z)V") \

DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidWindowManagerLayoutParams30, "android/view/WindowManager$LayoutParams", 30)
#undef JNI_CLASS_MEMBERS

#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 METHOD (getSystemWindowInsetTop,    "getSystemWindowInsetTop",     "()I") \
 METHOD (getSystemWindowInsetBottom, "getSystemWindowInsetBottom",  "()I") \
 METHOD (getSystemWindowInsetLeft,   "getSystemWindowInsetLeft",    "()I") \
 METHOD (getSystemWindowInsetRight,  "getSystemWindowInsetRight",   "()I") \
 METHOD (getStableInsetTop,          "getStableInsetTop",           "()I") \
 METHOD (getStableInsetBottom,       "getStableInsetBottom",        "()I") \
 METHOD (getStableInsetLeft,         "getStableInsetLeft",          "()I") \
 METHOD (getStableInsetRight,        "getStableInsetRight",         "()I") \
 METHOD (consumeSystemWindowInsets,  "consumeSystemWindowInsets",   "()Landroid/view/WindowInsets;") \

 DECLARE_JNI_CLASS (AndroidWindowInsets, "android/view/WindowInsets")
#undef JNI_CLASS_MEMBERS

#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 METHOD (getDisplayCutout, "getDisplayCutout", "()Landroid/view/DisplayCutout;") \
 METHOD (consumeDisplayCutout, "consumeDisplayCutout", "()Landroid/view/WindowInsets;")

 DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidWindowInsets28, "android/view/WindowInsets", 28)
#undef JNI_CLASS_MEMBERS

#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 METHOD (getInsets, "getInsets", "(I)Landroid/graphics/Insets;") \
 STATICFIELD (CONSUMED, "CONSUMED", "Landroid/view/WindowInsets;")

 DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidWindowInsets30, "android/view/WindowInsets", 30)
#undef JNI_CLASS_MEMBERS

#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 METHOD (getSafeInsetBottom, "getSafeInsetBottom", "()I") \
 METHOD (getSafeInsetLeft,   "getSafeInsetLeft",   "()I") \
 METHOD (getSafeInsetRight,  "getSafeInsetRight",  "()I") \
 METHOD (getSafeInsetTop,    "getSafeInsetTop",    "()I")

 DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidDisplayCutout, "android/view/DisplayCutout", 28)
#undef JNI_CLASS_MEMBERS

#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 FIELD (bottom, "bottom", "I") \
 FIELD (left, "left", "I") \
 FIELD (right, "right", "I") \
 FIELD (top, "top", "I")

 DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidGraphicsInsets, "android/graphics/Insets", 29)
#undef JNI_CLASS_MEMBERS

#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 STATICMETHOD (ime, "ime", "()I") \
 STATICMETHOD (displayCutout, "displayCutout", "()I") \
 STATICMETHOD (systemBars, "systemBars", "()I") \

 DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidWindowInsetsType, "android/view/WindowInsets$Type", 30)
#undef JNI_CLASS_MEMBERS

#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 FIELD (first,  "first",  "Ljava/lang/Object;") \
 FIELD (second, "second", "Ljava/lang/Object;") \

 DECLARE_JNI_CLASS (AndroidPair, "android/util/Pair")
#undef JNI_CLASS_MEMBERS

#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 METHOD (getBounds,       "getBounds",       "()Landroid/graphics/Rect;") \
 METHOD (getWindowInsets, "getWindowInsets", "()Landroid/view/WindowInsets;") \

 DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidWindowMetrics, "android/view/WindowMetrics", 30)
#undef JNI_CLASS_MEMBERS

#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 METHOD (hide,       "hide",       "()V") \

 DECLARE_JNI_CLASS (AndroidActionBar, "android/app/ActionBar")
#undef JNI_CLASS_MEMBERS

//==============================================================================
namespace
{
    enum
    {
        SYSTEM_UI_FLAG_VISIBLE = 0,
        SYSTEM_UI_FLAG_LOW_PROFILE = 1,
        SYSTEM_UI_FLAG_HIDE_NAVIGATION = 2,
        SYSTEM_UI_FLAG_FULLSCREEN = 4,
        SYSTEM_UI_FLAG_LAYOUT_STABLE = 256,
        SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 512,
        SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 1024,
        SYSTEM_UI_FLAG_IMMERSIVE = 2048,
        SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 4096
    };

    constexpr int fullScreenFlags = SYSTEM_UI_FLAG_HIDE_NAVIGATION | SYSTEM_UI_FLAG_FULLSCREEN | SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
    constexpr int FLAG_NOT_FOCUSABLE = 0x8;

    LocalRef<jobject> getCurrentOrMainActivity() noexcept
    {
        if (auto result = getCurrentActivity())
            return result;

        if (auto result = getMainActivity())
            return result;

        return {};
    }
}

//==============================================================================
static BorderSize<int> computeLogicalBorderSize (BorderSize<int> b, double displayScale)
{
    const auto getInset = [&] (int physicalSize) { return roundToInt (physicalSize / displayScale); };
    return { getInset (b.getTop()), getInset (b.getLeft()), getInset (b.getBottom()), getInset (b.getRight()) };
}

static BorderSize<int> androidDisplayCutoutToBorderSize (LocalRef<jobject> displayCutout, double displayScale)
{
    if (displayCutout == nullptr)
        return {};

    auto* env = getEnv();

    const auto getInset = [&] (jmethodID methodID) { return env->CallIntMethod (displayCutout, methodID); };

    return computeLogicalBorderSize ({ getInset (AndroidDisplayCutout.getSafeInsetTop),
                                       getInset (AndroidDisplayCutout.getSafeInsetLeft),
                                       getInset (AndroidDisplayCutout.getSafeInsetBottom),
                                       getInset (AndroidDisplayCutout.getSafeInsetRight) },
                                     displayScale);
}

static BorderSize<int> androidInsetsToBorderSize (LocalRef<jobject> insets, double displayScale)
{
    if (insets == nullptr)
        return {};

    auto* env = getEnv();

    const auto getInset = [&] (jfieldID fieldID) { return env->GetIntField (insets, fieldID); };

    return computeLogicalBorderSize ({ getInset (AndroidGraphicsInsets.top),
                                       getInset (AndroidGraphicsInsets.left),
                                       getInset (AndroidGraphicsInsets.bottom),
                                       getInset (AndroidGraphicsInsets.right) },
                                     displayScale);
}

class JuceInsets
{
    template <typename Display>
    static auto tieDisplay (Display& d) { return std::tie (d.safeAreaInsets, d.keyboardInsets); }

public:
    BorderSize<int> displayCutout, keyboard;

    static auto tie (      Displays::Display& d) { return tieDisplay (d); }
    static auto tie (const Displays::Display& d) { return tieDisplay (d); }

    auto tie() const { return std::tie (displayCutout, keyboard); }
};

static JuceInsets getInsetsFromAndroidWindowInsets (LocalRef<jobject> windowInsets, jint visibility, double scale)
{
    auto* env = getEnv();

    if (windowInsets == nullptr)
        return {};

    const auto systemAreas = std::invoke ([&]() -> BorderSize<int>
    {
        // Use the new WindowInsets API where available
        if (AndroidWindowInsets30.getInsets != nullptr)
        {
            const auto bars = env->CallStaticIntMethod (AndroidWindowInsetsType, AndroidWindowInsetsType.systemBars);
            const auto cutout = env->CallStaticIntMethod (AndroidWindowInsetsType, AndroidWindowInsetsType.displayCutout);
            const jint mask = cutout | bars;
            const LocalRef<jobject> insets { env->CallObjectMethod (windowInsets, AndroidWindowInsets30.getInsets, mask) };
            return androidInsetsToBorderSize (insets, scale);
        }

        // The WindowInsets API with combined cutout/system area reporting isn't available, so
        // use the old API instead.
        const auto currentTop    = env->CallIntMethod (windowInsets, AndroidWindowInsets.getSystemWindowInsetTop);
        const auto currentLeft   = env->CallIntMethod (windowInsets, AndroidWindowInsets.getSystemWindowInsetLeft);
        const auto currentBottom = env->CallIntMethod (windowInsets, AndroidWindowInsets.getSystemWindowInsetBottom);
        const auto currentRight  = env->CallIntMethod (windowInsets, AndroidWindowInsets.getSystemWindowInsetRight);

        const auto stableBottom = env->CallIntMethod (windowInsets, AndroidWindowInsets.getStableInsetBottom);

        // This is similar to the approach taken in the AndroidX library, see WindowInsetsCompat.java.
        // System UI insets are always posted to our window, even if the UI isn't showing on-screen.
        // Therefore, we check which UI is *actually* visible, and remove the insets for any invisible UI.
        const auto hasStatus = (visibility & SYSTEM_UI_FLAG_FULLSCREEN) == 0;
        const auto hasNav = (visibility & SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;

        const auto bottomInset = std::invoke ([&]
        {
            // This likely indicates that the IME is showing, and we want to respect the keyboard
            // insets in this case
            if (currentBottom > stableBottom)
                return currentBottom;

            if (hasNav)
                return currentBottom;

            return 0;
        });

        const auto baseBorder = computeLogicalBorderSize ({ hasStatus ? currentTop : 0,
                                                            hasNav ? currentLeft : 0,
                                                            bottomInset,
                                                            hasNav ? currentRight : 0 },
                                                          scale);

        if (AndroidWindowInsets28.getDisplayCutout == nullptr)
            return baseBorder;

        const LocalRef insets { env->CallObjectMethod (windowInsets, AndroidWindowInsets28.getDisplayCutout) };
        const auto cutouts = androidDisplayCutoutToBorderSize (insets, scale);
        return { jmax (baseBorder.getTop(),     cutouts.getTop()),
                 jmax (baseBorder.getLeft(),    cutouts.getLeft()),
                 jmax (baseBorder.getBottom(),  cutouts.getBottom()),
                 jmax (baseBorder.getRight(),   cutouts.getRight()) };
    });

    const auto keyboard = std::invoke ([&]() -> BorderSize<int>
    {
        if (AndroidWindowInsetsType.ime == nullptr || AndroidWindowInsets30.getInsets == nullptr)
            return {};

        // The IME insets may also include the system or cutout insets, but we expect the keyboard
        // insets to be strictly additive, so remove any insets we've already included in the system areas
        const auto ime = env->CallStaticIntMethod (AndroidWindowInsetsType, AndroidWindowInsetsType.ime);
        const auto bars = env->CallStaticIntMethod (AndroidWindowInsetsType, AndroidWindowInsetsType.systemBars);
        const auto cutout = env->CallStaticIntMethod (AndroidWindowInsetsType, AndroidWindowInsetsType.displayCutout);
        const jint mask = ime | cutout | bars;

        const LocalRef<jobject> insets { env->CallObjectMethod (windowInsets, AndroidWindowInsets30.getInsets, mask) };
        const auto unclamped = systemAreas.subtractedFrom (androidInsetsToBorderSize (insets, scale));
        return { jmax (0, unclamped.getTop()),
                 jmax (0, unclamped.getLeft()),
                 jmax (0, unclamped.getBottom()),
                 jmax (0, unclamped.getRight()) };
    });

    return { systemAreas, keyboard };
}

/* The usage of the KeyPress class relies on its keyCode member having the standard ASCII values
   represent ASCII keycodes. However in the native Android keycodes the values for special keys
   e.g. RETURN, F1-F12 overlap with the ASCII range. Hence we need to translate them.
*/
static constexpr int translateAndroidKeyCode (int keyCode) noexcept
{
    switch (keyCode)
    {
        case 7:   return '0';
        case 8:   return '1';
        case 9:   return '2';
        case 10:  return '3';
        case 11:  return '4';
        case 12:  return '5';
        case 13:  return '6';
        case 14:  return '7';
        case 15:  return '8';
        case 16:  return '9';
        case 17:  return '*';
        case 18:  return '#';
        case 19:  return KeyPress::upKey;             // KEYCODE_DPAD_UP
        case 20:  return KeyPress::downKey;           // KEYCODE_DPAD_DOWN
        case 21:  return KeyPress::leftKey;           // KEYCODE_DPAD_LEFT
        case 22:  return KeyPress::rightKey;          // KEYCODE_DPAD_RIGHT
        case 29:  return 'A';
        case 30:  return 'B';
        case 31:  return 'C';
        case 32:  return 'D';
        case 33:  return 'E';
        case 34:  return 'F';
        case 35:  return 'G';
        case 36:  return 'H';
        case 37:  return 'I';
        case 38:  return 'J';
        case 39:  return 'K';
        case 40:  return 'L';
        case 41:  return 'M';
        case 42:  return 'N';
        case 43:  return 'O';
        case 44:  return 'P';
        case 45:  return 'Q';
        case 46:  return 'R';
        case 47:  return 'S';
        case 48:  return 'T';
        case 49:  return 'U';
        case 50:  return 'V';
        case 51:  return 'W';
        case 52:  return 'X';
        case 53:  return 'Y';
        case 54:  return 'Z';
        case 55:  return ',';
        case 56:  return '.';
        case 61:  return KeyPress::tabKey;            // KEYCODE_TAB
        case 62:  return KeyPress::spaceKey;          // KEYCODE_SPACE
        case 66:  return KeyPress::returnKey;         // KEYCODE_ENTER
        case 67:  return KeyPress::backspaceKey;      // KEYCODE_DEL
        case 68:  return '`';
        case 69:  return '-';
        case 70:  return '=';
        case 71:  return '[';
        case 72:  return ']';
        case 73:  return '\\';
        case 74:  return ';';
        case 75:  return '\'';
        case 76:  return '/';
        case 77:  return '@';
        case 81:  return '+';
        case 85:  return KeyPress::playKey;           // KEYCODE_MEDIA_PLAY_PAUSE
        case 86:  return KeyPress::stopKey;           // KEYCODE_MEDIA_STOP
        case 87:  return KeyPress::fastForwardKey;    // KEYCODE_MEDIA_NEXT
        case 88:  return KeyPress::rewindKey;         // KEYCODE_MEDIA_PREVIOUS
        case 92:  return KeyPress::pageUpKey;         // KEYCODE_PAGE_UP
        case 93:  return KeyPress::pageDownKey;       // KEYCODE_PAGE_DOWN
        case 111: return KeyPress::escapeKey;         // KEYCODE_ESCAPE
        case 112: return KeyPress::deleteKey;         // KEYCODE_FORWARD_DEL
        case 122: return KeyPress::homeKey;           // KEYCODE_MOVE_HOME
        case 123: return KeyPress::endKey;            // KEYCODE_MOVE_END
        case 124: return KeyPress::insertKey;         // KEYCODE_INSERT
        case 131: return KeyPress::F1Key;             // KEYCODE_F1
        case 132: return KeyPress::F2Key;             // KEYCODE_F2
        case 133: return KeyPress::F3Key;             // KEYCODE_F3
        case 134: return KeyPress::F4Key;             // KEYCODE_F4
        case 135: return KeyPress::F5Key;             // KEYCODE_F5
        case 136: return KeyPress::F6Key;             // KEYCODE_F6
        case 137: return KeyPress::F7Key;             // KEYCODE_F7
        case 138: return KeyPress::F8Key;             // KEYCODE_F8
        case 139: return KeyPress::F9Key;             // KEYCODE_F9
        case 140: return KeyPress::F10Key;            // KEYCODE_F10
        case 141: return KeyPress::F11Key;            // KEYCODE_F11
        case 142: return KeyPress::F12Key;            // KEYCODE_F12
        case 144: return '0';
        case 145: return '1';
        case 146: return '2';
        case 147: return '3';
        case 148: return '4';
        case 149: return '5';
        case 150: return '6';
        case 151: return '7';
        case 152: return '8';
        case 153: return '9';
        case 154: return '/';
        case 155: return '*';
        case 156: return '-';
        case 157: return '+';
        case 158: return '.';
        case 159: return ',';
        case 161: return '=';
        case 162: return '(';
        case 163: return ')';

        default:  return 0;
    }
}

static constexpr int translateAndroidKeyboardFlags (int javaFlags) noexcept
{
    constexpr int metaShiftOn = 0x1;
    constexpr int metaAltOn   = 0x02;
    constexpr int metaCtrlOn  = 0x1000;

    int flags = 0;

    if ((javaFlags & metaShiftOn) != 0) flags |= ModifierKeys::shiftModifier;
    if ((javaFlags & metaAltOn) != 0)   flags |= ModifierKeys::altModifier;
    if ((javaFlags & metaCtrlOn) != 0)  flags |= ModifierKeys::ctrlModifier;

    return flags;
}

//==============================================================================
class AndroidComponentPeer final : public ComponentPeer,
                                   private ActivityLifecycleCallbacks
{
public:
    AndroidComponentPeer (Component& comp, int windowStyleFlags, void* nativeViewHandle)
        : ComponentPeer (comp, windowStyleFlags)
    {
        auto* env = getEnv();

        // NB: must not put this in the initialiser list, as it invokes a callback,
        // which will fail if the peer is only half-constructed.
        view = GlobalRef (LocalRef<jobject> (env->NewObject (ComponentPeerView, ComponentPeerView.create,
                                                             getAppContext().get(), (jboolean) component.isOpaque(),
                                                             (jlong) this)));

        userDidSupplyParent = nativeViewHandle != nullptr;

        if (userDidSupplyParent)
        {
            // we don't know if the user is holding on to a local ref to this, so
            // explicitly create a new one
            auto nativeView = LocalRef<jobject> (env->NewLocalRef (static_cast<jobject> (nativeViewHandle)));

            if (env->IsInstanceOf (nativeView.get(), AndroidActivity))
            {
                viewGroup = GlobalRef (nativeView);
                env->CallVoidMethod (viewGroup.get(), AndroidActivity.setContentView, view.get());
            }
            else if (env->IsInstanceOf (nativeView.get(), AndroidViewGroup))
            {
                viewGroup = GlobalRef (nativeView);
                LocalRef<jobject> layoutParams (env->NewObject (AndroidLayoutParams, AndroidLayoutParams.create, -2, -2));

                env->CallVoidMethod (view.get(), AndroidView.setLayoutParams, layoutParams.get());
                env->CallVoidMethod ((jobject) viewGroup.get(), AndroidViewGroup.addView, view.get());
            }
            else
            {
                // the native handle you passed as a second argument to Component::addToDesktop must
                // either be an Activity or a ViewGroup
                jassertfalse;
            }
        }
        else
        {
            LocalRef viewLayoutParams { env->NewObject (AndroidLayoutParams, AndroidLayoutParams.create, -2, -2) };
            env->CallVoidMethod (view.get(), AndroidView.setLayoutParams, viewLayoutParams.get());

            const auto rawPeerBounds = detail::ComponentHelpers::localPositionToRawPeerPos (comp, comp.getBoundsInParent().toFloat());
            const auto physicalBounds = Desktop::getInstance().getDisplays().logicalToPhysical (rawPeerBounds).toNearestInt();

            view.callVoidMethod (AndroidView.layout,
                                 physicalBounds.getX(), physicalBounds.getY(), physicalBounds.getRight(), physicalBounds.getBottom());

            LocalRef windowLayoutParams { env->NewObject (AndroidWindowManagerLayoutParams,
                                                          AndroidWindowManagerLayoutParams.createDefault) };

            if (Desktop::getInstance().getKioskModeComponent() != nullptr)
                refreshSystemBarsAndSetHidden (true);

            setUpLayoutParams (env, windowLayoutParams, physicalBounds);

            auto activity = getCurrentOrMainActivity();

            const LocalRef window { env->CallObjectMethod (activity, AndroidActivity.getWindow) };
            activityWindow = GlobalRef { window };
            const LocalRef attributes { env->CallObjectMethod (window, AndroidWindow.getAttributes) };

            static constexpr auto SOFT_INPUT_ADJUST_RESIZE = 0x10;
            env->SetIntField (attributes, AndroidWindowManagerLayoutParams.softInputMode, SOFT_INPUT_ADJUST_RESIZE);

            enableLayoutInCutout (env, attributes);

            // There's not much use for an action bar if we're only drawing JUCE content into the window
            if (const LocalRef actionBar { env->CallObjectMethod (activity, AndroidActivity.getActionBar) })
                env->CallVoidMethod (actionBar, AndroidActionBar.hide);

            auto flags = env->GetIntField (windowLayoutParams, AndroidWindowManagerLayoutParams.flags);
            flags |= FLAG_NOT_FOCUSABLE;
            env->SetIntField (windowLayoutParams, AndroidWindowManagerLayoutParams.flags, flags);

            viewGroup = GlobalRef { LocalRef { env->CallObjectMethod (activity, AndroidActivity.getWindowManager) } };
            env->CallVoidMethod (viewGroup, AndroidViewManager.addView, view.get(), windowLayoutParams.get());

            // It *seems* as though adding a new focusable window will cause the system UI to show
            // if previously hidden, even if the new window also wants the system UI to be hidden.
            // Setting the focusable flag after first adding the window stops the system UI from
            // reappearing. I don't know why this works!
            env->SetIntField (windowLayoutParams, AndroidWindowManagerLayoutParams.flags, flags & ~FLAG_NOT_FOCUSABLE);
            env->CallVoidMethod (viewGroup, AndroidViewManager.updateViewLayout, view.get(), windowLayoutParams.get());
        }

        auto activity = getCurrentOrMainActivity();

        const LocalRef window { env->CallObjectMethod (activity, AndroidActivity.getWindow) };
        const LocalRef decorView { env->CallObjectMethod (window, AndroidWindow.getDecorView) };
        const auto listener = CreateJavaInterface (new ViewWindowInsetsListener,
                                                   "android/view/View$OnApplyWindowInsetsListener");
        env->CallVoidMethod (decorView,
                             AndroidView.setOnApplyWindowInsetsListener,
                             listener.get());

        if (isFocused())
            handleFocusGain();
    }

    ~AndroidComponentPeer() override
    {
        auto* env = getEnv();

        auto activity = getCurrentOrMainActivity();

        const LocalRef window { env->CallObjectMethod (activity, AndroidActivity.getWindow) };
        const LocalRef decorView { env->CallObjectMethod (window, AndroidWindow.getDecorView) };

        env->CallVoidMethod (decorView, AndroidView.setOnApplyWindowInsetsListener, (jobject) nullptr);

        env->CallVoidMethod (view, ComponentPeerView.clear);
        frontWindow = nullptr;

        removeView();
        setSystemBarsTransparent();
    }

    static void removeViewFromActivity (jobject localView)
    {
        if (localView == nullptr)
            return;

        auto* env = getEnv();

        if (LocalRef<jobject> parent { env->CallObjectMethod (localView, AndroidView.getParent) })
            env->CallVoidMethod (parent, AndroidViewGroup.removeView, localView);
    }

    void removeView()
    {
        auto* env = getEnv();

        if (userDidSupplyParent)
        {
            if (env->IsInstanceOf (viewGroup, AndroidActivity))
            {
                removeViewFromActivity (view);
                return;
            }

            if (env->IsInstanceOf (viewGroup, AndroidViewGroup))
            {
                env->CallVoidMethod (viewGroup, AndroidViewGroup.removeView, view.get());
                return;
            }

            // The parent was not an activity or view group?
            jassertfalse;
            return;
        }

        if (fullScreen)
        {
            removeViewFromActivity (view);
            return;
        }

        if (env->IsInstanceOf (viewGroup, AndroidWindowManager))
        {
            env->CallVoidMethod (viewGroup, AndroidWindowManager.removeViewImmediate, view.get());
            return;
        }

        // The view's owner didn't have the expected type!
        jassertfalse;
    }

    void* getNativeHandle() const override
    {
        return (void*) view.get();
    }

    void setVisible (bool shouldBeVisible) override
    {
        GlobalRef localView (view);

        callOnMessageThread ([localView, shouldBeVisible]
        {
            localView.callVoidMethod (ComponentPeerView.setVisible, shouldBeVisible);
        });
    }

    void setTitle (const String& title) override
    {
        view.callVoidMethod (ComponentPeerView.setViewName, javaString (title).get());
    }

    void setBounds (const Rectangle<int>& userRect, bool isNowFullScreen) override
    {
        auto bounds = Desktop::getInstance().getDisplays().logicalToPhysical (userRect);

        if (MessageManager::getInstance()->isThisTheMessageThread())
        {
            auto* env = getEnv();

            if (fullScreen != isNowFullScreen && ! userDidSupplyParent)
            {
                removeView();

                fullScreen = isNowFullScreen;

                LocalRef windowLayoutParams { env->NewObject (AndroidWindowManagerLayoutParams,
                                                              AndroidWindowManagerLayoutParams.createDefault) };

                setUpLayoutParams (env, windowLayoutParams.get(), bounds);

                if (isNowFullScreen)
                {
                    if (auto activity = getCurrentOrMainActivity())
                        env->CallVoidMethod (activity, AndroidActivity.addContentView, view.get(), windowLayoutParams.get());
                }
                else if (env->IsInstanceOf (viewGroup, AndroidViewManager))
                {
                    env->CallVoidMethod (viewGroup.get(),
                                         AndroidViewManager.addView,
                                         view.get(),
                                         windowLayoutParams.get());
                }
                else
                {
                    // Not fullscreen but the viewgroup isn't a viewmanager/windowmanager instance
                    jassertfalse;
                }

                refreshSystemBarsAndSetHidden (navBarsHidden);
            }
            else if (! fullScreen)
            {
                if (viewGroup != nullptr && ! userDidSupplyParent)
                {
                    LocalRef windowLayoutParams { env->NewObject (AndroidWindowManagerLayoutParams,
                                                                  AndroidWindowManagerLayoutParams.createDefault) };

                    setUpLayoutParams (env, windowLayoutParams.get(), bounds);

                    env->CallVoidMethod (viewGroup.get(),
                                         AndroidViewManager.updateViewLayout,
                                         view.get(),
                                         windowLayoutParams.get());

                    refreshSystemBarsAndSetHidden (navBarsHidden);
                }
                else
                {
                    view.callVoidMethod (AndroidView.layout,
                                         bounds.getX(),
                                         bounds.getY(),
                                         bounds.getRight(),
                                         bounds.getBottom());

                }
            }

            fullScreen = isNowFullScreen;
        }
        else
        {
            GlobalRef localView (view);

            MessageManager::callAsync ([localView, bounds]
            {
                localView.callVoidMethod (AndroidView.layout,
                                          bounds.getX(), bounds.getY(), bounds.getRight(), bounds.getBottom());
            });
        }
    }

    Rectangle<int> getBounds() const override
    {
        Rectangle<int> bounds (view.callIntMethod (AndroidView.getLeft),
                               view.callIntMethod (AndroidView.getTop),
                               view.callIntMethod (AndroidView.getWidth),
                               view.callIntMethod (AndroidView.getHeight));

        return Desktop::getInstance().getDisplays().physicalToLogical (bounds);
    }

    void handleScreenSizeChange() override
    {
        ComponentPeer::handleScreenSizeChange();

        if (isFullScreen())
            setFullScreen (true);
    }

    Point<int> getScreenPosition() const
    {
        const auto physical = getViewLocationOnScreen (getEnv(), view.get());
        return Desktop::getInstance().getDisplays().physicalToLogical (physical);
    }

    Point<float> localToGlobal (Point<float> relativePosition) override
    {
        return relativePosition + (getScreenPosition().toFloat());
    }

    using ComponentPeer::localToGlobal;

    Point<float> globalToLocal (Point<float> screenPosition) override
    {
        return screenPosition - (getScreenPosition().toFloat());
    }

    using ComponentPeer::globalToLocal;

    void setMinimised (bool /*shouldBeMinimised*/) override
    {
        // n/a
    }

    bool isMinimised() const override
    {
        return false;
    }

    bool isShowing() const override
    {
        return true;
    }

    void setFullScreen (bool shouldBeFullScreen) override
    {
        refreshSystemBarsAndSetHidden (shouldNavBarsBeHidden (shouldBeFullScreen));

        auto newBounds = std::invoke ([&]
        {
            // Even if we're "fullscreen", Android might be displaying our app in a split-screen
            // mode. We treat fullscreen mode as just filling the extent of the window provided for
            // us.
            if (shouldBeFullScreen)
                if (auto* display = Desktop::getInstance().getDisplays().getPrimaryDisplay())
                    return display->userArea;

            return lastNonFullscreenBounds.isEmpty() ? getBounds() : lastNonFullscreenBounds;
        });

        if (! newBounds.isEmpty())
            setBounds (newBounds, shouldBeFullScreen);

        component.repaint();
    }

    bool isFullScreen() const override
    {
        return fullScreen;
    }

    void setIcon (const Image& /*newIcon*/) override
    {
        // n/a
    }

    bool contains (Point<int> localPos, bool) const override
    {
        const auto scaled = detail::ComponentHelpers::rawPeerPositionToLocal (component, localPos);
        return component.getLocalBounds().contains (scaled);
    }

    OptionalBorderSize getFrameSizeIfPresent() const override
    {
        // TODO
        return {};
    }

    BorderSize<int> getFrameSize() const override
    {
        // TODO
        return {};
    }

    bool setAlwaysOnTop (bool /*alwaysOnTop*/) override
    {
        // TODO
        return false;
    }

    void toFront (bool makeActive) override
    {
        // Avoid calling bringToFront excessively: it's very slow
        if (frontWindow != this)
        {
            view.callVoidMethod (AndroidView.bringToFront);
            frontWindow = this;
        }

        if (makeActive)
            grabFocus();

        handleBroughtToFront();
    }

    void toBehind (ComponentPeer*) override
    {
        // TODO
    }

    //==============================================================================
    void handleMouseDownCallback (int index, Point<float> sysPos, int64 time)
    {
        lastMousePos = Desktop::getInstance().getDisplays().physicalToLogical (sysPos);
        auto pos = globalToLocal (lastMousePos);

        // this forces a mouse-enter/up event, in case for some reason we didn't get a mouse-up before.
        handleMouseEvent (MouseInputSource::InputSourceType::touch,
                          pos,
                          ModifierKeys::currentModifiers.withoutMouseButtons(),
                          MouseInputSource::defaultPressure,
                          MouseInputSource::defaultOrientation,
                          time,
                          {},
                          index);

        if (isValidPeer (this))
            handleMouseDragCallback (index, sysPos, time);
    }

    void handleMouseDragCallback (int index, Point<float> sysPos, int64 time)
    {
        lastMousePos = Desktop::getInstance().getDisplays().physicalToLogical (sysPos);
        auto pos = globalToLocal (lastMousePos);

        jassert (index < 64);
        touchesDown = (touchesDown | (1 << (index & 63)));

        ModifierKeys::currentModifiers = ModifierKeys::currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier);

        handleMouseEvent (MouseInputSource::InputSourceType::touch,
                          pos,
                          ModifierKeys::currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier),
                          MouseInputSource::defaultPressure,
                          MouseInputSource::defaultOrientation,
                          time,
                          {},
                          index);
    }

    void handleMouseUpCallback (int index, Point<float> sysPos, int64 time)
    {
        lastMousePos = Desktop::getInstance().getDisplays().physicalToLogical (sysPos);
        auto pos = globalToLocal (lastMousePos);

        jassert (index < 64);
        touchesDown = (touchesDown & ~(1 << (index & 63)));

        if (touchesDown == 0)
            ModifierKeys::currentModifiers = ModifierKeys::currentModifiers.withoutMouseButtons();

        handleMouseEvent (MouseInputSource::InputSourceType::touch,
                          pos,
                          ModifierKeys::currentModifiers.withoutMouseButtons(),
                          MouseInputSource::defaultPressure,
                          MouseInputSource::defaultOrientation,
                          time,
                          {},
                          index);

        handleMouseEvent (MouseInputSource::InputSourceType::touch,
                          MouseInputSource::offscreenMousePos,
                          ModifierKeys::currentModifiers.withoutMouseButtons(),
                          MouseInputSource::defaultPressure,
                          MouseInputSource::defaultOrientation,
                          time,
                          {},
                          index);
    }

    void handleAccessibilityHoverCallback (int command, Point<float> sysPos, int64)
    {
        enum
        {
            TYPE_VIEW_HOVER_ENTER = 0x00000080,
            TYPE_VIEW_HOVER_EXIT  = 0x00000100,

            ACTION_HOVER_ENTER    = 0x00000009,
            ACTION_HOVER_MOVE     = 0x00000007,
            ACTION_HOVER_EXIT     = 0x0000000a
        };

        if (auto* topHandler = component.getAccessibilityHandler())
        {
            const auto rawPeerPos = Desktop::getInstance().getDisplays().physicalToLogical (sysPos);
            const auto localPos = detail::ComponentHelpers::rawPeerPositionToLocal (component, rawPeerPos);

            if (auto* virtualHandler = topHandler->getChildAt (localPos.roundToInt()))
            {
                switch (command)
                {
                    case ACTION_HOVER_ENTER:
                    case ACTION_HOVER_MOVE:
                        AccessibilityNativeHandle::sendAccessibilityEventImpl (*virtualHandler, TYPE_VIEW_HOVER_ENTER, 0);
                        break;

                    case ACTION_HOVER_EXIT:
                        AccessibilityNativeHandle::sendAccessibilityEventImpl (*virtualHandler, TYPE_VIEW_HOVER_EXIT, 0);
                        break;
                }
            }
        }
    }

    static void handleKeyDownCallback (JNIEnv*, AndroidComponentPeer& t, int k, int kc, int kbFlags)
    {
        ModifierKeys::currentModifiers = ModifierKeys::currentModifiers.withOnlyMouseButtons()
                                                                       .withFlags (translateAndroidKeyboardFlags (kbFlags));
        t.handleKeyPress (translateAndroidKeyCode (k), static_cast<juce_wchar> (kc));
    }

    static void handleKeyUpCallback (JNIEnv*, [[maybe_unused]] AndroidComponentPeer& t, [[maybe_unused]] int k, [[maybe_unused]] int kc)
    {
    }

    static void handleBackButtonCallback (JNIEnv* env, AndroidComponentPeer& t)
    {
        bool handled = false;

        if (auto* app = JUCEApplicationBase::getInstance())
            handled = app->backButtonPressed();

        if (t.isKioskModeComponent())
            t.refreshSystemBarsAndSetHidden (t.navBarsHidden);

        if (! handled)
        {
            LocalRef<jobject> activity (getCurrentActivity());

            if (activity != nullptr)
            {
                if (const auto finishMethod = AndroidActivity.finish)
                    env->CallVoidMethod (activity.get(), finishMethod);
            }
        }
    }

    static void handleKeyboardHiddenCallback (JNIEnv*, [[maybe_unused]] AndroidComponentPeer& t)
    {
        Component::unfocusAllComponents();
    }

    static void handleAppPausedCallback (JNIEnv*, [[maybe_unused]] AndroidComponentPeer& t) {}

    static void handleAppResumedCallback (JNIEnv*, AndroidComponentPeer& t)
    {
        if (t.isKioskModeComponent())
            t.refreshSystemBarsAndSetHidden (t.navBarsHidden);
    }

    static jlong handleGetFocusedTextInputTargetCallback (JNIEnv*, AndroidComponentPeer& t)
    {
        return reinterpret_cast<jlong> (t.findCurrentTextInputTarget());
    }

    static void handleMovedOrResizedCallback (JNIEnv*, AndroidComponentPeer& t)
    {
        t.handleMovedOrResized();
    }

    //==============================================================================
    AccessibilityNativeHandle* getNativeHandleForViewId (jint virtualViewId) const
    {
        if (auto* handler = (virtualViewId == HOST_VIEW_ID
                                 ? component.getAccessibilityHandler()
                                 : AccessibilityNativeHandle::getAccessibilityHandlerForVirtualViewId (virtualViewId)))
        {
            return handler->getNativeImplementation();
        }

        return nullptr;
    }

    static jobject getNativeViewCallback (JNIEnv*, const AndroidComponentPeer& t, jint virtualViewId)
    {
        if (auto* handle = t.getNativeHandleForViewId (virtualViewId))
            return handle->getNativeView (virtualViewId);

        return nullptr;
    }

    static jboolean populateAccessibilityNodeInfoCallback (JNIEnv*, const AndroidComponentPeer& t, jint virtualViewId, jobject info)
    {
        if (auto* handle = t.getNativeHandleForViewId (virtualViewId))
        {
            handle->populateNodeInfo (info, virtualViewId);
            return true;
        }

        return false;
    }

    static jboolean handlePerformActionCallback (JNIEnv*, const AndroidComponentPeer& t, jint virtualViewId, jint action, jobject arguments)
    {
        if (auto* handle = t.getNativeHandleForViewId (virtualViewId))
            return handle->performAction (action, arguments);

        return false;
    }

    static jobject getFocusViewIdForHandler (JNIEnv* env, const AccessibilityHandler* handler)
    {
        if (handler != nullptr)
            return env->NewObject (JavaInteger,
                                   JavaInteger.constructor,
                                   handler->getNativeImplementation()->getVirtualViewId());

        return nullptr;
    }

    static jobject getInputFocusViewIdCallback (JNIEnv* env, AndroidComponentPeer& t)
    {
        if (auto* comp = dynamic_cast<Component*> (t.findCurrentTextInputTarget()))
            return getFocusViewIdForHandler (env, comp->getAccessibilityHandler());

        return nullptr;
    }

    static jobject getAccessibilityFocusViewIdCallback (JNIEnv* env, const AndroidComponentPeer& t)
    {
        if (auto* handler = t.component.getAccessibilityHandler())
        {
            if (auto* modal = Component::getCurrentlyModalComponent())
            {
                if (! t.component.isParentOf (modal)
                     && t.component.isCurrentlyBlockedByAnotherModalComponent())
                {
                    if (auto* modalHandler = modal->getAccessibilityHandler())
                    {
                        if (auto* focusChild = modalHandler->getChildFocus())
                            return getFocusViewIdForHandler (env, focusChild);

                        return getFocusViewIdForHandler (env, modalHandler);
                    }
                }
            }

            if (auto* focusChild = handler->getChildFocus())
                return getFocusViewIdForHandler (env, focusChild);
        }

        return nullptr;
    }

    //==============================================================================
    bool isFocused() const override
    {
        if (view != nullptr)
            return view.callBooleanMethod (AndroidView.hasFocus);

        return false;
    }

    void grabFocus() override
    {
        if (view != nullptr)
            view.callBooleanMethod (AndroidView.requestFocus);
    }

    static void handleFocusChangeCallback (JNIEnv*, AndroidComponentPeer& t, bool hasFocus)
    {
        if (t.isFullScreen())
            t.setFullScreen (true);

        if (hasFocus)
            t.handleFocusGain();
        else
            t.handleFocusLoss();
    }

    void textInputRequired (Point<int>, TextInputTarget& target) override
    {
        const auto region = target.getHighlightedRegion();
        view.callVoidMethod (ComponentPeerView.showKeyboard,
                             static_cast<jint> (target.getKeyboardType()),
                             static_cast<jint> (region.getStart()),
                             static_cast<jint> (region.getEnd()));
    }

    void closeInputMethodContext() override
    {
        getEnv()->CallVoidMethod (view, ComponentPeerView.closeInputMethodContext);
    }

    void dismissPendingTextInput() override
    {
        closeInputMethodContext();

        view.callVoidMethod (ComponentPeerView.hideKeyboard);
    }

    //==============================================================================
    static void handleDoFrameCallback (JNIEnv*, AndroidComponentPeer& t, [[maybe_unused]] int64 frameTimeNanos)
    {
        const auto timestampSec = (double) frameTimeNanos / (double) 1'000'000'000;
        t.callVBlankListeners (timestampSec);
    }

    static void handlePaintCallback (JNIEnv* env, AndroidComponentPeer& t, jobject canvas, jobject paint)
    {
        LocalRef<jobject> rect { env->CallObjectMethod (canvas, AndroidCanvas.getClipBounds) };
        auto left   = env->GetIntField (rect, AndroidRect.left);
        auto top    = env->GetIntField (rect, AndroidRect.top);
        auto right  = env->GetIntField (rect, AndroidRect.right);
        auto bottom = env->GetIntField (rect, AndroidRect.bottom);

        auto clip = Rectangle<int>::leftTopRightBottom (left, top, right, bottom);

        if (clip.isEmpty())
            return;

        auto sizeNeeded = clip.getWidth() * clip.getHeight();

        if (t.sizeAllocated < sizeNeeded)
        {
            t.buffer.clear();
            t.sizeAllocated = sizeNeeded;
            t.buffer = GlobalRef (LocalRef<jobject> ((jobject) env->NewIntArray (sizeNeeded)));
        }

        if (jint* dest = env->GetIntArrayElements ((jintArray) t.buffer.get(), nullptr))
        {
            {
                Image temp (new PreallocatedImage (clip.getWidth(), clip.getHeight(),
                                                   dest, ! t.component.isOpaque()));

                {
                    LowLevelGraphicsSoftwareRenderer g (temp);
                    g.setOrigin (-clip.getPosition());
                    const auto scale = Desktop::getInstance().getDisplays().getPrimaryDisplay()->scale
                                     / Desktop::getInstance().getGlobalScaleFactor();
                    g.addTransform (AffineTransform::scale ((float) scale));
                    t.handlePaint (g);
                }
            }

            env->ReleaseIntArrayElements ((jintArray) t.buffer.get(), dest, 0);

            env->CallVoidMethod (canvas, AndroidCanvas.drawBitmap, (jintArray) t.buffer.get(), 0, clip.getWidth(),
                                 (jfloat) clip.getX(), (jfloat) clip.getY(),
                                 clip.getWidth(), clip.getHeight(), true, paint);
        }
    }

    void repaint (const Rectangle<int>& userArea) override
    {
        const auto area = Desktop::getInstance().getDisplays().logicalToPhysical (userArea.toFloat()).toNearestInt();

        GlobalRef localView (view);

        callOnMessageThread ([area, localView]
        {
            localView.callVoidMethod (AndroidView.invalidate,
                                      area.getX(), area.getY(), area.getRight(), area.getBottom());
        });
    }

    void performAnyPendingRepaintsNow() override
    {
        // TODO
    }

    void setAlpha (float /*newAlpha*/) override
    {
        // TODO
    }

    StringArray getAvailableRenderingEngines() override
    {
        return StringArray ("Software Renderer");
    }

    void appStyleChanged() override
    {
        JUCE_ASSERT_MESSAGE_THREAD
        refreshSystemBarsAndSetHidden (navBarsHidden);
    }

    //==============================================================================
    inline static Point<float> lastMousePos{};
    inline static int64 touchesDown = 0;

    //==============================================================================
    struct StartupActivityCallbackListener final : public ActivityLifecycleCallbacks
    {
        void onActivityStarted (jobject /*activity*/) override
        {
            forceDisplayUpdate();

            AndroidComponentPeer::startupActivityCallbackListener.reset();
        }

        ActivityLifecycleCallbackForwarder forwarder { GlobalRef { getAppContext() }, this };
    };

    class MainActivityWindowLayoutListener : public AndroidInterfaceImplementer
    {
    private:
        jobject invoke (jobject proxy, jobject method, jobjectArray args) override
        {
            auto* env = getEnv();
            auto methodName = juceString ((jstring) env->CallObjectMethod (method, JavaMethod.getName));

            if (methodName == "onLayoutChange")
            {
                jassert (env->GetArrayLength (args) == 9);

                forceDisplayUpdate();

                return nullptr;
            }

            // invoke base class
            return AndroidInterfaceImplementer::invoke (proxy, method, args);
        }
    };

private:
    template <auto Member>
    static void mouseCallbackWrapper (JNIEnv*, AndroidComponentPeer& t, jint i, jfloat x, jfloat y, jlong time) { return (t.*Member) (i, Point<float> { x, y }, time); }

    static Point<int> getViewLocationOnScreen (JNIEnv* env, jobject view)
    {
        if (view == nullptr)
            return {};

        LocalRef position { env->NewIntArray (2) };
        env->CallVoidMethod (view, AndroidView.getLocationOnScreen, position.get());

        jint* const screenPosition = env->GetIntArrayElements (position.get(), nullptr);
        Point<int> pos (screenPosition[0], screenPosition[1]);
        env->ReleaseIntArrayElements (position.get(), screenPosition, 0);

        return pos;
    }

    static Point<int> getActivityLocationOnScreen (JNIEnv* env, jobject activity)
    {
        if (activity == nullptr)
            return {};

        LocalRef mainWindow { env->CallObjectMethod (activity, AndroidActivity.getWindow) };

        if (mainWindow == nullptr)
            return {};

        return getViewLocationOnScreen (env, env->CallObjectMethod (mainWindow, AndroidWindow.getDecorView));
    }

    static void enableLayoutInCutout (JNIEnv* env, jobject windowLayoutParams)
    {
        if (const auto fieldID = AndroidWindowManagerLayoutParams28.layoutInDisplayCutoutMode)
        {
            const jint layoutMode = getAndroidSDKVersion() >= 30
                                    ? LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
                                    : LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
            env->SetIntField (windowLayoutParams, fieldID, layoutMode);
        }
    }

    void setUpLayoutParams (JNIEnv* env, jobject layoutParams, Rectangle<int> bounds) const
    {
        constexpr jint MATCH_PARENT = -1;
        env->SetIntField (layoutParams, AndroidLayoutParams.width,  fullScreen ? MATCH_PARENT : bounds.getWidth());
        env->SetIntField (layoutParams, AndroidLayoutParams.height, fullScreen ? MATCH_PARENT : bounds.getHeight());

        if (! env->IsInstanceOf (layoutParams, AndroidWindowManagerLayoutParams))
            return;

        // When userDidSupplyParent is false, we're laying out the window within the bounds
        // provided to the activity, and the userRect is in global screen space.
        // For fullscreen windows, it's easiest to ask Android to size the view
        // appropriately by matching the parent view.
        // For non-fullscreen windows, despite FLAG_LAYOUT_IN_SCREEN below, the view
        // coordinates here appear to be interpreted as relative to the bounds of the
        // activity's main window, rather than relative to the display.
        // This matters when the app window's top-left isn't flush with the top-left of
        // the display, which frequently happens in split-screen mode.

        const auto posInActivity = fullScreen
                                 ? Point<int>{}
                                 : bounds.getPosition() - getActivityLocationOnScreen (env, getMainActivity());

        env->SetIntField (layoutParams, AndroidWindowManagerLayoutParams.x, posInActivity.x);
        env->SetIntField (layoutParams, AndroidWindowManagerLayoutParams.y, posInActivity.y);

        env->SetIntField (layoutParams, AndroidWindowManagerLayoutParams.gravity, GRAVITY_TOP | GRAVITY_LEFT);

        enableLayoutInCutout (env, layoutParams);

        if (const auto fieldID = AndroidWindowManagerLayoutParams28.layoutInDisplayCutoutMode)
        {
            const jint layoutMode = getAndroidSDKVersion() >= 30
                                  ? LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
                                  : LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
            env->SetIntField (layoutParams, fieldID, layoutMode);
        }

        // In split-screen mode these flags seem to go missing, so make sure they're still
        // set. Without these, the navigation bar insets and background may display incorrectly.
        auto flags = env->GetIntField (layoutParams, AndroidWindowManagerLayoutParams.flags);
        flags |= FLAG_NOT_TOUCH_MODAL
                 | FLAG_LAYOUT_IN_SCREEN
                 | FLAG_LAYOUT_NO_LIMITS
                 | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;

        if (getAndroidSDKVersion() >= 30)
        {
            env->CallVoidMethod (layoutParams, AndroidWindowManagerLayoutParams30.setFitInsetsSides, (jint) 0);
            env->CallVoidMethod (layoutParams, AndroidWindowManagerLayoutParams30.setFitInsetsIgnoringVisibility, (jboolean) true);
        }

        env->SetIntField (layoutParams, AndroidWindowManagerLayoutParams.flags, flags);

        env->SetIntField (layoutParams,
                          AndroidWindowManagerLayoutParams.format,
                          component.isOpaque() ? PIXEL_FORMAT_OPAQUE : PIXEL_FORMAT_TRANSPARENT);
        env->SetIntField (layoutParams, AndroidWindowManagerLayoutParams.type, TYPE_APPLICATION);

        static constexpr auto SOFT_INPUT_ADJUST_RESIZE = 0x10;
        env->SetIntField (layoutParams, AndroidWindowManagerLayoutParams.softInputMode, SOFT_INPUT_ADJUST_RESIZE);
    }

    //==============================================================================
   #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
    METHOD   (create,                           "<init>",                        "(Landroid/content/Context;ZJ)V") \
    METHOD   (clear,                            "clear",                         "()V") \
    METHOD   (setViewName,                      "setViewName",                   "(Ljava/lang/String;)V") \
    METHOD   (setVisible,                       "setVisible",                    "(Z)V") \
    METHOD   (isVisible,                        "isVisible",                     "()Z") \
    METHOD   (showKeyboard,                     "showKeyboard",                  "(III)V") \
    METHOD   (hideKeyboard,                     "hideKeyboard",                  "()V") \
    METHOD   (closeInputMethodContext,          "closeInputMethodContext",       "()V") \
    METHOD   (setSystemUiVisibilityCompat,      "setSystemUiVisibilityCompat",   "(Landroid/view/Window;ZZ)V") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::handleDoFrameCallback>,                    "handleDoFrame",                                    "(JJ)V") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::handlePaintCallback>,                      "handlePaint",                                      "(JLandroid/graphics/Canvas;Landroid/graphics/Paint;)V") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::handleKeyDownCallback>,                    "handleKeyDown",                                    "(JIII)V") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::handleKeyUpCallback>,                      "handleKeyUp",                                      "(JII)V") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::handleBackButtonCallback>,                 "handleBackButton",                                 "(J)V") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::handleKeyboardHiddenCallback>,             "handleKeyboardHidden",                             "(J)V") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::handleGetFocusedTextInputTargetCallback>,  "getFocusedTextInputTargetPointer",                 "(J)J") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::handleMovedOrResizedCallback>,             "viewSizeChanged",                                  "(J)V") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::handleFocusChangeCallback>,                "focusChanged",                                     "(JZ)V") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::handleAppPausedCallback>,                  "handleAppPaused",                                  "(J)V") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::handleAppResumedCallback>,                 "handleAppResumed",                                 "(J)V")  \
    CALLBACK (generatedCallback<&AndroidComponentPeer::getNativeViewCallback>,                    "getNativeView",                                    "(JI)Landroid/view/View;") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::populateAccessibilityNodeInfoCallback>,    "populateAccessibilityNodeInfo",                    "(JILandroid/view/accessibility/AccessibilityNodeInfo;)Z") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::handlePerformActionCallback>,              "handlePerformAction",                              "(JIILandroid/os/Bundle;)Z") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::getInputFocusViewIdCallback>,              "getInputFocusViewId",                              "(J)Ljava/lang/Integer;") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::getAccessibilityFocusViewIdCallback>,      "getAccessibilityFocusViewId",                      "(J)Ljava/lang/Integer;") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::textInputTargetIsTextInputActive>,         "textInputTargetIsTextInputActive",                 "(J)Z") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::textInputTargetGetHighlightedRegionBegin>, "textInputTargetGetHighlightedRegionBegin",         "(J)I") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::textInputTargetGetHighlightedRegionEnd>,   "textInputTargetGetHighlightedRegionEnd",           "(J)I") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::textInputTargetSetHighlightedRegion>,      "textInputTargetSetHighlightedRegion",              "(JII)V") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::textInputTargetGetTextInRange>,            "textInputTargetGetTextInRange",                    "(JII)Ljava/lang/String;") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::textInputTargetInsertTextAtCaret>,         "textInputTargetInsertTextAtCaret",                 "(JLjava/lang/String;)V") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::textInputTargetGetCaretPosition>,          "textInputTargetGetCaretPosition",                  "(J)I") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::textInputTargetGetTotalNumChars>,          "textInputTargetGetTotalNumChars",                  "(J)I") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::textInputTargetGetCharIndexForPoint>,      "textInputTargetGetCharIndexForPoint",              "(JLandroid/graphics/Point;)I") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::textInputTargetGetKeyboardType>,           "textInputTargetGetKeyboardType",                   "(J)I") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::textInputTargetSetTemporaryUnderlining>,   "textInputTargetSetTemporaryUnderlining",           "(JLjava/util/List;)V") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::mouseCallbackWrapper<&AndroidComponentPeer::handleMouseDownCallback>>,          "handleMouseDown",               "(JIFFJ)V") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::mouseCallbackWrapper<&AndroidComponentPeer::handleMouseDragCallback>>,          "handleMouseDrag",               "(JIFFJ)V") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::mouseCallbackWrapper<&AndroidComponentPeer::handleMouseUpCallback>>,            "handleMouseUp",                 "(JIFFJ)V") \
    CALLBACK (generatedCallback<&AndroidComponentPeer::mouseCallbackWrapper<&AndroidComponentPeer::handleAccessibilityHoverCallback>>, "handleAccessibilityHover",      "(JIFFJ)V") \

    DECLARE_JNI_CLASS_WITH_BYTECODE (ComponentPeerView, "com/rmsl/juce/ComponentPeerView", 16, javaComponentPeerView)
   #undef JNI_CLASS_MEMBERS

    static jboolean textInputTargetIsTextInputActive (JNIEnv*, const TextInputTarget& t)
    {
        return t.isTextInputActive();
    }

    static jint textInputTargetGetHighlightedRegionBegin (JNIEnv*, const TextInputTarget& t)
    {
        return t.getHighlightedRegion().getStart();
    }

    static jint textInputTargetGetHighlightedRegionEnd (JNIEnv*, const TextInputTarget& t)
    {
        return t.getHighlightedRegion().getEnd();
    }

    static void textInputTargetSetHighlightedRegion (JNIEnv*, TextInputTarget& t, jint b, jint e)
    {
        t.setHighlightedRegion ({ b, e });
    }

    static jstring textInputTargetGetTextInRange (JNIEnv* env, const TextInputTarget& t, jint b, jint e)
    {
        return env->NewStringUTF (t.getTextInRange ({ b, e }).toUTF8());
    }

    static void textInputTargetInsertTextAtCaret (JNIEnv*, TextInputTarget& t, jstring text)
    {
        t.insertTextAtCaret (juceString (text));
    }

    static jint textInputTargetGetCaretPosition (JNIEnv*, const TextInputTarget& t)
    {
        return t.getCaretPosition();
    }

    static jint textInputTargetGetTotalNumChars (JNIEnv*, const TextInputTarget& t)
    {
        return t.getTotalNumChars();
    }

    static jint textInputTargetGetCharIndexForPoint (JNIEnv* env, const TextInputTarget& t, jobject point)
    {
        return t.getCharIndexForPoint ({ env->GetIntField (point, AndroidPoint.x),
                                         env->GetIntField (point, AndroidPoint.y) });
    }

    static jint textInputTargetGetKeyboardType (JNIEnv*, TextInputTarget& t)
    {
        return t.getKeyboardType();
    }

    static std::optional<Range<int>> getRangeFromPair (JNIEnv* env, jobject pair)
    {
        if (pair == nullptr)
            return {};

        const auto first  = env->GetObjectField (pair, AndroidPair.first);
        const auto second = env->GetObjectField (pair, AndroidPair.second);

        if (first == nullptr || second == nullptr)
            return {};

        const auto begin = env->CallIntMethod (first,  JavaInteger.intValue);
        const auto end   = env->CallIntMethod (second, JavaInteger.intValue);

        return Range<int> { begin, end };
    }

    static Array<Range<int>> javaListOfPairToArrayOfRange (JNIEnv* env, jobject list)
    {
        if (list == nullptr)
            return {};

        Array<Range<int>> result;

        for (jint i = 0; i < env->CallIntMethod (list, JavaList.size); ++i)
            if (const auto range = getRangeFromPair (env, env->CallObjectMethod (list, JavaList.get, i)))
                result.add (*range);

        return result;
    }

    static void textInputTargetSetTemporaryUnderlining (JNIEnv* env, TextInputTarget& t, jobject list)
    {
        t.setTemporaryUnderlining (javaListOfPairToArrayOfRange (env, list));
    }

    class ViewWindowInsetsListener final : public AndroidInterfaceImplementer
    {
    private:
        jobject onApplyWindowInsets (JNIEnv* env, LocalRef<jobject>, LocalRef<jobject> insets) const
        {
            forceDisplayUpdate();

            if (const auto fieldId = AndroidWindowInsets30.CONSUMED)
                return env->GetStaticObjectField (AndroidWindowInsets30, fieldId);

            auto* consumed = env->CallObjectMethod (insets, AndroidWindowInsets.consumeSystemWindowInsets);

            if (const auto fieldId = AndroidWindowInsets28.consumeDisplayCutout)
                return env->CallObjectMethod (consumed, fieldId);

            return consumed;
        }

        jobject invoke (jobject proxy, jobject method, jobjectArray args) override
        {
            auto* env = getEnv();
            auto methodName = juceString ((jstring) env->CallObjectMethod (method, JavaMethod.getName));

            if (methodName == "onApplyWindowInsets")
            {
                jassert (env->GetArrayLength (args) == 2);

                return onApplyWindowInsets (env,
                                            LocalRef { env->GetObjectArrayElement (args, 0) },
                                            LocalRef { env->GetObjectArrayElement (args, 1) });
            }

            // invoke base class
            return AndroidInterfaceImplementer::invoke (proxy, method, args);
        }
    };

    //==============================================================================
    struct PreallocatedImage final : public ImagePixelData
    {
        PreallocatedImage (int width_, int height_, jint* data_, bool hasAlpha_)
            : ImagePixelData (Image::ARGB, width_, height_), data (data_), hasAlpha (hasAlpha_)
        {
            if (hasAlpha_)
                zeromem (data_, static_cast<size_t> (width * height) * sizeof (jint));
        }

        ~PreallocatedImage() override
        {
            if (hasAlpha)
            {
                auto pix = (PixelARGB*) data;

                for (int i = width * height; --i >= 0;)
                {
                    pix->unpremultiply();
                    ++pix;
                }
            }
        }

        std::unique_ptr<ImageType> createType() const override
        {
            return std::make_unique<SoftwareImageType>();
        }

        std::unique_ptr<LowLevelGraphicsContext> createLowLevelContext() override
        {
            return std::make_unique<LowLevelGraphicsSoftwareRenderer> (Image (this));
        }

        void initialiseBitmapData (Image::BitmapData& bm, int x, int y, Image::BitmapData::ReadWriteMode /*mode*/) override
        {
            bm.lineStride = width * static_cast<int> (sizeof (jint));
            bm.pixelStride = static_cast<int> (sizeof (jint));
            bm.pixelFormat = Image::ARGB;
            const auto offset = (size_t) x + (size_t) y * (size_t) width;
            bm.data = (uint8*) (data + offset);
            bm.size = sizeof (jint) * (((size_t) height * (size_t) width) - offset);
        }

        ImagePixelData::Ptr clone() override
        {
            auto s = new PreallocatedImage (width, height, nullptr, hasAlpha);
            s->allocatedData.malloc (sizeof (jint) * static_cast<size_t> (width * height));
            s->data = s->allocatedData;
            memcpy (s->data, data, sizeof (jint) * static_cast<size_t> (width * height));
            return s;
        }

    private:
        jint* data;
        HeapBlock<jint> allocatedData;
        bool hasAlpha;

        JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PreallocatedImage)
    };

    //==============================================================================
    bool isKioskModeComponent() const
    {
        if (auto* kiosk = Desktop::getInstance().getKioskModeComponent())
            return kiosk->getPeer() == this;

        return false;
    }

    bool shouldNavBarsBeHidden (bool shouldBeFullScreen) const
    {
        return (shouldBeFullScreen && isKioskModeComponent());
    }

    void refreshSystemBarsAndSetHidden (bool hidden)
    {
        // The system may show the bars again, e.g when navigating away from the app and
        // back again. Therefore, we should call setSystemUiVisibilityCompat each time to
        // ensure that the system bars get put back into the expected state.
        navBarsHidden = hidden;
        getEnv()->CallVoidMethod (view,
                                  ComponentPeerView.setSystemUiVisibilityCompat,
                                  activityWindow.get(),
                                  (jboolean) ! navBarsHidden,
                                  (jboolean) (getAppStyle() == Style::light));

        setSystemBarsTransparent();
    }

    void setSystemBarsTransparent()
    {
        if (activityWindow == nullptr)
            return;

        auto* env = getEnv();

        constexpr jint fullyTransparent = 0;
        env->CallVoidMethod (activityWindow, AndroidWindow.setStatusBarColor, fullyTransparent);
        env->CallVoidMethod (activityWindow, AndroidWindow.setNavigationBarColor, fullyTransparent);

        env->CallVoidMethod (activityWindow, AndroidWindow.setFlags, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);

        if (getAndroidSDKVersion() >= 29)
            env->CallVoidMethod (activityWindow, AndroidWindow29.setNavigationBarContrastEnforced, (jboolean) false);
    }

    template <typename Callback>
    static void callOnMessageThread (Callback&& callback)
    {
        if (MessageManager::getInstance()->isThisTheMessageThread())
            callback();
        else
            MessageManager::callAsync (std::forward<Callback> (callback));
    }

    //==============================================================================
    friend class Displays;
    inline static AndroidComponentPeer* frontWindow = nullptr;
    inline static std::optional<StartupActivityCallbackListener> startupActivityCallbackListener;

    static constexpr jint GRAVITY_LEFT = 0x3, GRAVITY_TOP = 0x30;
    static constexpr jint TYPE_APPLICATION = 0x2;
    static constexpr jint TYPE_APPLICATION_PANEL = 1000;
    static constexpr jint FLAG_NOT_TOUCH_MODAL = 0x20, FLAG_LAYOUT_IN_SCREEN = 0x100;
    static constexpr jint FLAG_LAYOUT_NO_LIMITS = 0x200;
    static constexpr jint FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = (jint) 0x80000000;
    static constexpr jint PIXEL_FORMAT_OPAQUE = -1, PIXEL_FORMAT_TRANSPARENT = -2;
    static constexpr jint LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS = 0x3;
    static constexpr jint LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES = 0x1;

    GlobalRef view, viewGroup, buffer, activityWindow;
    bool userDidSupplyParent = false, fullScreen = false, navBarsHidden = false;
    int sizeAllocated = 0;

    //==============================================================================
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidComponentPeer)
};

//==============================================================================
ComponentPeer* Component::createNewPeer (int styleFlags, void* nativeWindow)
{
    return new AndroidComponentPeer (*this, styleFlags, nativeWindow);
}

//==============================================================================
bool Desktop::canUseSemiTransparentWindows() noexcept
{
    return true;
}

class Desktop::NativeDarkModeChangeDetectorImpl  : private ActivityLifecycleCallbacks
{
public:
    NativeDarkModeChangeDetectorImpl() = default;

    bool isDarkModeEnabled() const noexcept  { return darkModeEnabled; }

private:
    void onActivityStarted (jobject) override
    {
        updateMode();
    }

    void onActivityConfigurationChanged (jobject) override
    {
        updateMode();
    }

    void updateMode()
    {
        const auto current = getDarkModeSetting();

        if (std::exchange (darkModeEnabled, current) != current)
            Desktop::getInstance().darkModeChanged();
    }

    static bool getDarkModeSetting()
    {
        auto* env = getEnv();

        const LocalRef<jobject> resources (env->CallObjectMethod (getAppContext().get(), AndroidContext.getResources));
        const LocalRef<jobject> configuration (env->CallObjectMethod (resources, AndroidResources.getConfiguration));

        const auto uiMode = env->GetIntField (configuration, AndroidConfiguration.uiMode);

        return ((uiMode & UI_MODE_NIGHT_MASK) == UI_MODE_NIGHT_YES);
    }

    static constexpr int UI_MODE_NIGHT_MASK      = 0x00000030,
                         UI_MODE_NIGHT_NO        = 0x00000010,
                         UI_MODE_NIGHT_UNDEFINED = 0x00000000,
                         UI_MODE_NIGHT_YES       = 0x00000020;

    bool darkModeEnabled = getDarkModeSetting();
    ActivityLifecycleCallbackForwarder forwarder { GlobalRef { getAppContext() }, this };

    //==============================================================================
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeDarkModeChangeDetectorImpl)
};

std::unique_ptr<Desktop::NativeDarkModeChangeDetectorImpl> Desktop::createNativeDarkModeChangeDetectorImpl()
{
    return std::make_unique<NativeDarkModeChangeDetectorImpl>();
}

bool Desktop::isDarkModeActive() const
{
    return nativeDarkModeChangeDetectorImpl->isDarkModeEnabled();
}

double Desktop::getDefaultMasterScale()
{
    return 1.0;
}

Desktop::DisplayOrientation Desktop::getCurrentOrientation() const
{
    enum
    {
        ROTATION_0   = 0,
        ROTATION_90  = 1,
        ROTATION_180 = 2,
        ROTATION_270 = 3
    };

    JNIEnv* env = getEnv();
    LocalRef<jstring> windowServiceString (javaString ("window"));

    LocalRef<jobject> windowManager = LocalRef<jobject> (env->CallObjectMethod (getAppContext().get(), AndroidContext.getSystemService, windowServiceString.get()));

    if (windowManager.get() != nullptr)
    {
        LocalRef<jobject> display = LocalRef<jobject> (env->CallObjectMethod (windowManager, AndroidWindowManager.getDefaultDisplay));

        if (display.get() != nullptr)
        {
            int rotation = env->CallIntMethod (display, AndroidDisplay.getRotation);

            switch (rotation)
            {
                case ROTATION_0:   return upright;
                case ROTATION_90:  return rotatedAntiClockwise;
                case ROTATION_180: return upsideDown;
                case ROTATION_270: return rotatedClockwise;
            }
        }
    }

    jassertfalse;
    return upright;
}

bool detail::MouseInputSourceList::addSource()
{
    addSource (sources.size(), MouseInputSource::InputSourceType::touch);
    return true;
}

bool detail::MouseInputSourceList::canUseTouch() const
{
    return true;
}

Point<float> MouseInputSource::getCurrentRawMousePosition()
{
    return AndroidComponentPeer::lastMousePos;
}

void MouseInputSource::setRawMousePosition (Point<float>)
{
    // not needed
}

//==============================================================================
bool KeyPress::isKeyCurrentlyDown (int /*keyCode*/)
{
    // TODO
    return false;
}

JUCE_API void JUCE_CALLTYPE Process::hide()
{
    auto* env = getEnv();
    LocalRef<jobject> currentActivity (getCurrentActivity().get());

    if (env->CallBooleanMethod (currentActivity.get(), AndroidActivity.moveTaskToBack, true) == 0)
    {
        GlobalRef intent (LocalRef<jobject> (env->NewObject (AndroidIntent, AndroidIntent.constructor)));
        env->CallObjectMethod (intent, AndroidIntent.setAction,   javaString ("android.intent.action.MAIN")  .get());
        env->CallObjectMethod (intent, AndroidIntent.addCategory, javaString ("android.intent.category.HOME").get());

        env->CallVoidMethod (currentActivity.get(), AndroidContext.startActivity, intent.get());
    }
}

//==============================================================================
// TODO
JUCE_API bool JUCE_CALLTYPE Process::isForegroundProcess() { return true; }
JUCE_API void JUCE_CALLTYPE Process::makeForegroundProcess() {}

//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 METHOD (show,                   "show",                 "()V") \
 METHOD (getWindow,              "getWindow",            "()Landroid/view/Window;")

DECLARE_JNI_CLASS (AndroidDialog, "android/app/Dialog")
#undef JNI_CLASS_MEMBERS

#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 METHOD (construct,                   "<init>",                 "(Landroid/content/Context;)V") \
 METHOD (create,                      "create",                 "()Landroid/app/AlertDialog;") \
 METHOD (setTitle,                    "setTitle",               "(Ljava/lang/CharSequence;)Landroid/app/AlertDialog$Builder;") \
 METHOD (setMessage,                  "setMessage",             "(Ljava/lang/CharSequence;)Landroid/app/AlertDialog$Builder;") \
 METHOD (setCancelable,               "setCancelable",          "(Z)Landroid/app/AlertDialog$Builder;") \
 METHOD (setOnCancelListener,         "setOnCancelListener",    "(Landroid/content/DialogInterface$OnCancelListener;)Landroid/app/AlertDialog$Builder;") \
 METHOD (setPositiveButton,           "setPositiveButton",      "(Ljava/lang/CharSequence;Landroid/content/DialogInterface$OnClickListener;)Landroid/app/AlertDialog$Builder;") \
 METHOD (setNegativeButton,           "setNegativeButton",      "(Ljava/lang/CharSequence;Landroid/content/DialogInterface$OnClickListener;)Landroid/app/AlertDialog$Builder;") \
 METHOD (setNeutralButton,            "setNeutralButton",       "(Ljava/lang/CharSequence;Landroid/content/DialogInterface$OnClickListener;)Landroid/app/AlertDialog$Builder;")

DECLARE_JNI_CLASS (AndroidAlertDialogBuilder, "android/app/AlertDialog$Builder")
#undef JNI_CLASS_MEMBERS

#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 METHOD (dismiss,    "dismiss",  "()V")

DECLARE_JNI_CLASS (AndroidDialogInterface, "android/content/DialogInterface")
#undef JNI_CLASS_MEMBERS

#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \

DECLARE_JNI_CLASS (AndroidDialogOnClickListener, "android/content/DialogInterface$OnClickListener")
#undef JNI_CLASS_MEMBERS

//==============================================================================
class DialogListener final : public AndroidInterfaceImplementer
{
public:
    explicit DialogListener (std::function<void()> cb) : callback (std::move (cb)) {}

    jobject invoke (jobject proxy, jobject method, jobjectArray args) override
    {
        auto* env = getEnv();
        auto methodName = juceString ((jstring) env->CallObjectMethod (method, JavaMethod.getName));

        if (methodName == "onCancel" || methodName == "onClick")
        {
            auto* dialog = env->GetObjectArrayElement (args, 0);
            env->CallVoidMethod (dialog, AndroidDialogInterface.dismiss);

            NullCheckedInvocation::invoke (callback);

            return nullptr;
        }

        // invoke base class
        return AndroidInterfaceImplementer::invoke (proxy, method, args);
    }

private:
    std::function<void()> callback;
};

//==============================================================================
static bool androidScreenSaverEnabled = true;

void Desktop::setScreenSaverEnabled (bool shouldEnable)
{
    constexpr auto FLAG_KEEP_SCREEN_ON = 0x80;

    if (shouldEnable != androidScreenSaverEnabled)
    {
        LocalRef<jobject> activity (getMainActivity());

        if (activity != nullptr)
        {
            auto* env = getEnv();

            LocalRef<jobject> mainWindow (env->CallObjectMethod (activity.get(), AndroidActivity.getWindow));
            env->CallVoidMethod (mainWindow.get(), AndroidWindow.setFlags, shouldEnable ? 0 : FLAG_KEEP_SCREEN_ON, FLAG_KEEP_SCREEN_ON);
        }

        androidScreenSaverEnabled = shouldEnable;
    }
}

bool Desktop::isScreenSaverEnabled()
{
    return androidScreenSaverEnabled;
}

//==============================================================================
void Desktop::setKioskComponent (Component* kioskComp, bool enableOrDisable, [[maybe_unused]] bool allowMenusAndBars)
{
    if (AndroidComponentPeer* peer = dynamic_cast<AndroidComponentPeer*> (kioskComp->getPeer()))
        peer->setFullScreen (enableOrDisable);
    else
        jassertfalse; // (this should have been checked by the caller)
}

//==============================================================================
static jint getAndroidOrientationFlag (int orientations) noexcept
{
    enum
    {
        SCREEN_ORIENTATION_LANDSCAPE          = 0,
        SCREEN_ORIENTATION_PORTRAIT           = 1,
        SCREEN_ORIENTATION_USER               = 2,
        SCREEN_ORIENTATION_REVERSE_LANDSCAPE  = 8,
        SCREEN_ORIENTATION_REVERSE_PORTRAIT   = 9,
        SCREEN_ORIENTATION_USER_LANDSCAPE     = 11,
        SCREEN_ORIENTATION_USER_PORTRAIT      = 12,
    };

    switch (orientations)
    {
        case Desktop::upright:                                          return (jint) SCREEN_ORIENTATION_PORTRAIT;
        case Desktop::upsideDown:                                       return (jint) SCREEN_ORIENTATION_REVERSE_PORTRAIT;
        case Desktop::upright + Desktop::upsideDown:                    return (jint) SCREEN_ORIENTATION_USER_PORTRAIT;
        case Desktop::rotatedAntiClockwise:                             return (jint) SCREEN_ORIENTATION_LANDSCAPE;
        case Desktop::rotatedClockwise:                                 return (jint) SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
        case Desktop::rotatedClockwise + Desktop::rotatedAntiClockwise: return (jint) SCREEN_ORIENTATION_USER_LANDSCAPE;
        default:                                                        return (jint) SCREEN_ORIENTATION_USER;
    }
}

void Desktop::allowedOrientationsChanged()
{
    LocalRef<jobject> activity (getMainActivity());

    if (activity != nullptr)
        getEnv()->CallVoidMethod (activity.get(), AndroidActivity.setRequestedOrientation, getAndroidOrientationFlag (allowedOrientations));
}

//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 METHOD (create,          "<init>",         "()V") \
 FIELD  (density,         "density",        "F") \
 FIELD  (widthPixels,     "widthPixels",    "I") \
 FIELD  (heightPixels,    "heightPixels",   "I")

DECLARE_JNI_CLASS (AndroidDisplayMetrics, "android/util/DisplayMetrics")
#undef JNI_CLASS_MEMBERS

//==============================================================================
void Displays::findDisplays (float masterScale)
{
    auto* env = getEnv();

    LocalRef<jstring> windowServiceString (javaString ("window"));

    LocalRef<jobject> windowManager (env->CallObjectMethod (getAppContext(), AndroidContext.getSystemService, windowServiceString.get()));
    LocalRef<jobject> display (env->CallObjectMethod (windowManager, AndroidWindowManager.getDefaultDisplay));

    LocalRef<jobject> displayMetrics (env->NewObject (AndroidDisplayMetrics, AndroidDisplayMetrics.create));
    env->CallVoidMethod (display, AndroidDisplay17.getRealMetrics, displayMetrics.get());

    Display d;
    d.isMain = true;

    d.scale = env->GetFloatField (displayMetrics, AndroidDisplayMetrics.density);
    d.dpi = (d.scale * 160.f);
    d.scale *= masterScale;

    d.totalArea = Rectangle<int> (env->GetIntField (displayMetrics, AndroidDisplayMetrics.widthPixels),
                                  env->GetIntField (displayMetrics, AndroidDisplayMetrics.heightPixels)) / d.scale;

    LocalRef activity { getMainActivity() };
    LocalRef mainWindow { activity != nullptr
                          ? env->CallObjectMethod (activity, AndroidActivity.getWindow)
                          : nullptr };
    LocalRef decorView { mainWindow != nullptr
                         ? env->CallObjectMethod (mainWindow, AndroidWindow.getDecorView)
                         : nullptr };
    static constexpr jint androidContentViewId = 0x01020002 /* android.R.id.content */;
    LocalRef contentView { decorView != nullptr
                           ? env->CallObjectMethod (decorView, AndroidView.findViewById, androidContentViewId)
                           : nullptr };

    LocalRef insetsNative { decorView != nullptr
                            ? env->CallObjectMethod (decorView, AndroidView.getRootWindowInsets)
                            : nullptr };

    const auto isMultiWindow = activity != nullptr && env->CallBooleanMethod (activity, AndroidActivity.isInMultiWindowMode);

    if (insetsNative != nullptr)
    {
        // If we're in multi-window mode, the system UI bars are always visible
        const auto visibility = isMultiWindow ? 0 : env->CallIntMethod (decorView, AndroidView.getWindowSystemUiVisibility);
        JuceInsets::tie (d) = getInsetsFromAndroidWindowInsets (insetsNative, visibility, d.scale).tie();
    }

    static const auto sdkVersion = getAndroidSDKVersion();

    if (sdkVersion >= 30)
    {
        const LocalRef<jobject> windowMetrics (env->CallObjectMethod (windowManager, AndroidWindowManager30.getCurrentWindowMetrics));
        const LocalRef<jobject> bounds (env->CallObjectMethod (windowMetrics, AndroidWindowMetrics.getBounds));
        d.userArea = (Rectangle<int>::leftTopRightBottom (env->GetIntField (bounds, AndroidRect.left),
                                                          env->GetIntField (bounds, AndroidRect.top),
                                                          env->GetIntField (bounds, AndroidRect.right),
                                                          env->GetIntField (bounds, AndroidRect.bottom)) / d.scale);
    }
    else
    {
        d.userArea = std::invoke ([&]
        {
            // No content view yet; approximate with display size
            if (contentView == nullptr)
                return d.totalArea;

            const auto topLeft = AndroidComponentPeer::getViewLocationOnScreen (env, contentView);

            // This may not be correct for split-screen mode on older devices, but there also
            // doesn't seem to be a reliable way of getting this information, so this'll have to do.
            const auto contentSize = Rectangle { topLeft.x,
                                                 topLeft.y,
                                                 env->CallIntMethod (contentView, AndroidView.getWidth),
                                                 env->CallIntMethod (contentView, AndroidView.getHeight) } / d.scale;

            if (contentSize.isEmpty())
                return d.totalArea;

            return contentSize;
        });
    }

    if (activity != nullptr)
    {
        if (contentView != nullptr)
        {
            static bool hasAddedMainActivityListener = false;

            if (! std::exchange (hasAddedMainActivityListener, true))
            {
                env->CallVoidMethod (contentView, AndroidView.addOnLayoutChangeListener,
                                     CreateJavaInterface (new AndroidComponentPeer::MainActivityWindowLayoutListener,
                                                          "android/view/View$OnLayoutChangeListener").get());
            }
        }
    }
    else if (! AndroidComponentPeer::startupActivityCallbackListener.has_value())
    {
        AndroidComponentPeer::startupActivityCallbackListener.emplace();
    }

    displays.add (d);
}

//==============================================================================
Image detail::WindowingHelpers::createIconForFile (const File& /*file*/)
{
    return {};
}

//==============================================================================
class MouseCursor::PlatformSpecificHandle
{
public:
    PlatformSpecificHandle (const MouseCursor::StandardCursorType)      {}
    PlatformSpecificHandle (const detail::CustomMouseCursorInfo&)       {}

    static void showInWindow (PlatformSpecificHandle*, ComponentPeer*)  {}
};

//==============================================================================
bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& /*files*/, bool /*canMove*/,
                                                           Component* /*srcComp*/, std::function<void()> /*callback*/)
{
    jassertfalse;    // no such thing on Android!
    return false;
}

bool DragAndDropContainer::performExternalDragDropOfText (const String& /*text*/, Component* /*srcComp*/,
                                                          std::function<void()> /*callback*/)
{
    jassertfalse;    // no such thing on Android!
    return false;
}

//==============================================================================
void LookAndFeel::playAlertSound()
{
}

//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 METHOD (getText,      "getText",            "()Ljava/lang/CharSequence;") \
 METHOD (setText,      "setText",            "(Ljava/lang/CharSequence;)V")

DECLARE_JNI_CLASS (AndroidClipboardManager, "android/content/ClipboardManager")
#undef JNI_CLASS_MEMBERS

//==============================================================================
void SystemClipboard::copyTextToClipboard (const String& text)
{
    auto* env = getEnv();

    LocalRef<jobject> clipboardManager (env->CallObjectMethod (getAppContext().get(), AndroidContext.getSystemService, javaString ("clipboard").get()));
    env->CallVoidMethod (clipboardManager.get(), AndroidClipboardManager.setText, javaString (text).get());
}

String SystemClipboard::getTextFromClipboard()
{
    auto* env = getEnv();

    LocalRef<jobject> clipboardManager (env->CallObjectMethod (getAppContext().get(), AndroidContext.getSystemService, javaString ("clipboard").get()));
    LocalRef<jobject> charSequence (env->CallObjectMethod (clipboardManager.get(), AndroidClipboardManager.getText));

    if (charSequence == nullptr)
        return {};

    return juceString (LocalRef<jstring> ((jstring) env->CallObjectMethod (charSequence.get(), JavaCharSequence.toString)));
}

//==============================================================================
constexpr int extendedKeyModifier           = 0x10000;

const int KeyPress::spaceKey                = ' ';
const int KeyPress::returnKey               = extendedKeyModifier + 2;
const int KeyPress::escapeKey               = extendedKeyModifier + 3;
const int KeyPress::backspaceKey            = extendedKeyModifier + 4;
const int KeyPress::leftKey                 = extendedKeyModifier + 5;
const int KeyPress::rightKey                = extendedKeyModifier + 6;
const int KeyPress::upKey                   = extendedKeyModifier + 7;
const int KeyPress::downKey                 = extendedKeyModifier + 8;
const int KeyPress::pageUpKey               = extendedKeyModifier + 9;
const int KeyPress::pageDownKey             = extendedKeyModifier + 10;
const int KeyPress::endKey                  = extendedKeyModifier + 11;
const int KeyPress::homeKey                 = extendedKeyModifier + 12;
const int KeyPress::deleteKey               = extendedKeyModifier + 13;
const int KeyPress::insertKey               = extendedKeyModifier + 14;
const int KeyPress::tabKey                  = extendedKeyModifier + 15;
const int KeyPress::F1Key                   = extendedKeyModifier + 16;
const int KeyPress::F2Key                   = extendedKeyModifier + 17;
const int KeyPress::F3Key                   = extendedKeyModifier + 18;
const int KeyPress::F4Key                   = extendedKeyModifier + 19;
const int KeyPress::F5Key                   = extendedKeyModifier + 20;
const int KeyPress::F6Key                   = extendedKeyModifier + 21;
const int KeyPress::F7Key                   = extendedKeyModifier + 22;
const int KeyPress::F8Key                   = extendedKeyModifier + 23;
const int KeyPress::F9Key                   = extendedKeyModifier + 24;
const int KeyPress::F10Key                  = extendedKeyModifier + 25;
const int KeyPress::F11Key                  = extendedKeyModifier + 26;
const int KeyPress::F12Key                  = extendedKeyModifier + 27;
const int KeyPress::F13Key                  = extendedKeyModifier + 28;
const int KeyPress::F14Key                  = extendedKeyModifier + 29;
const int KeyPress::F15Key                  = extendedKeyModifier + 30;
const int KeyPress::F16Key                  = extendedKeyModifier + 31;
const int KeyPress::F17Key                  = extendedKeyModifier + 32;
const int KeyPress::F18Key                  = extendedKeyModifier + 33;
const int KeyPress::F19Key                  = extendedKeyModifier + 34;
const int KeyPress::F20Key                  = extendedKeyModifier + 35;
const int KeyPress::F21Key                  = extendedKeyModifier + 36;
const int KeyPress::F22Key                  = extendedKeyModifier + 37;
const int KeyPress::F23Key                  = extendedKeyModifier + 38;
const int KeyPress::F24Key                  = extendedKeyModifier + 39;
const int KeyPress::F25Key                  = extendedKeyModifier + 40;
const int KeyPress::F26Key                  = extendedKeyModifier + 41;
const int KeyPress::F27Key                  = extendedKeyModifier + 42;
const int KeyPress::F28Key                  = extendedKeyModifier + 43;
const int KeyPress::F29Key                  = extendedKeyModifier + 44;
const int KeyPress::F30Key                  = extendedKeyModifier + 45;
const int KeyPress::F31Key                  = extendedKeyModifier + 46;
const int KeyPress::F32Key                  = extendedKeyModifier + 47;
const int KeyPress::F33Key                  = extendedKeyModifier + 48;
const int KeyPress::F34Key                  = extendedKeyModifier + 49;
const int KeyPress::F35Key                  = extendedKeyModifier + 50;
const int KeyPress::numberPad0              = extendedKeyModifier + 51;
const int KeyPress::numberPad1              = extendedKeyModifier + 52;
const int KeyPress::numberPad2              = extendedKeyModifier + 53;
const int KeyPress::numberPad3              = extendedKeyModifier + 54;
const int KeyPress::numberPad4              = extendedKeyModifier + 55;
const int KeyPress::numberPad5              = extendedKeyModifier + 56;
const int KeyPress::numberPad6              = extendedKeyModifier + 57;
const int KeyPress::numberPad7              = extendedKeyModifier + 58;
const int KeyPress::numberPad8              = extendedKeyModifier + 59;
const int KeyPress::numberPad9              = extendedKeyModifier + 60;
const int KeyPress::numberPadAdd            = extendedKeyModifier + 61;
const int KeyPress::numberPadSubtract       = extendedKeyModifier + 62;
const int KeyPress::numberPadMultiply       = extendedKeyModifier + 63;
const int KeyPress::numberPadDivide         = extendedKeyModifier + 64;
const int KeyPress::numberPadSeparator      = extendedKeyModifier + 65;
const int KeyPress::numberPadDecimalPoint   = extendedKeyModifier + 66;
const int KeyPress::numberPadEquals         = extendedKeyModifier + 67;
const int KeyPress::numberPadDelete         = extendedKeyModifier + 68;
const int KeyPress::playKey                 = extendedKeyModifier + 69;
const int KeyPress::stopKey                 = extendedKeyModifier + 70;
const int KeyPress::fastForwardKey          = extendedKeyModifier + 71;
const int KeyPress::rewindKey               = extendedKeyModifier + 72;

//==============================================================================
#ifdef JUCE_PUSH_NOTIFICATIONS_ACTIVITY
 struct JuceActivityNewIntentListener
 {
     #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
      CALLBACK (appNewIntent, "appNewIntent", "(Landroid/content/Intent;)V") \
      CALLBACK (appOnResume,  "appOnResume",  "()V")

      DECLARE_JNI_CLASS (JavaActivity, JUCE_PUSH_NOTIFICATIONS_ACTIVITY)
     #undef JNI_CLASS_MEMBERS

     static void JNICALL appNewIntent (JNIEnv*, jobject /*activity*/, jobject intentData)
     {
         juce_handleNotificationIntent (static_cast<void*> (intentData));
     }

     static void JNICALL appOnResume (JNIEnv*, jobject)
     {
         juce_handleOnResume();
     }
 };
#endif

} // namespace juce
