diff --git a/.gitmodules b/.gitmodules index f4a9c7e1..da9339d7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "cspot/bell"] path = cspot/bell - url = https://github.com/feelfreelinux/bell - branch = develop + url = https://github.com/tobiasguyer/bell + branch = master diff --git a/.vscode/settings.json b/.vscode/settings.json index d876addd..9d06ecab 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,5 +8,94 @@ "--background-index", "--compile-commands-dir=${workspaceFolder}/targets/cli/build" ], - "editor.tabSize": 2 + "editor.tabSize": 2, + "files.associations": { + "vector": "cpp", + "memory": "cpp", + "chrono": "cpp", + "variant": "cpp", + "mutex": "cpp", + "deque": "cpp", + "array": "cpp", + "ranges": "cpp", + "span": "cpp", + "xstring": "cpp", + "xutility": "cpp", + "algorithm": "cpp", + "any": "cpp", + "atomic": "cpp", + "bit": "cpp", + "cctype": "cpp", + "charconv": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "codecvt": "cpp", + "compare": "cpp", + "complex": "cpp", + "concepts": "cpp", + "condition_variable": "cpp", + "csignal": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "exception": "cpp", + "filesystem": "cpp", + "format": "cpp", + "forward_list": "cpp", + "fstream": "cpp", + "functional": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "ios": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "iterator": "cpp", + "limits": "cpp", + "list": "cpp", + "locale": "cpp", + "map": "cpp", + "new": "cpp", + "numeric": "cpp", + "optional": "cpp", + "ostream": "cpp", + "queue": "cpp", + "random": "cpp", + "ratio": "cpp", + "regex": "cpp", + "set": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "string": "cpp", + "system_error": "cpp", + "thread": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "typeindex": "cpp", + "typeinfo": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "utility": "cpp", + "valarray": "cpp", + "xfacet": "cpp", + "xhash": "cpp", + "xiosbase": "cpp", + "xlocale": "cpp", + "xlocbuf": "cpp", + "xlocinfo": "cpp", + "xlocmes": "cpp", + "xlocmon": "cpp", + "xlocnum": "cpp", + "xloctime": "cpp", + "xmemory": "cpp", + "xtr1common": "cpp", + "xtree": "cpp" + } } \ No newline at end of file diff --git a/cspot/bell b/cspot/bell index e8373736..2bb04074 160000 --- a/cspot/bell +++ b/cspot/bell @@ -1 +1 @@ -Subproject commit e83737367a08b5a5a1f652a7ecb97a0d926929dd +Subproject commit 2bb040741d923291d4908e36c15e5cf6bc1a8b7b diff --git a/cspot/include/CDNAudioFile.h b/cspot/include/CDNAudioFile.h index 90cf8286..1b93fb02 100644 --- a/cspot/include/CDNAudioFile.h +++ b/cspot/include/CDNAudioFile.h @@ -21,6 +21,7 @@ class CDNAudioFile { public: CDNAudioFile(const std::string& cdnUrl, const std::vector& audioKey); +#ifndef CONFIG_BELL_NOCODEC /** * @brief Opens connection to the provided cdn url, and fetches track metadata. */ @@ -35,7 +36,27 @@ class CDNAudioFile { * @returns amount of bytes read */ size_t readBytes(uint8_t* dst, size_t bytes); +#else + /** + * @brief Opens connection to the provided cdn url, and fetches track header. + * + * @param header_size + * + * @returns char* where to read data from + */ + uint8_t* openStream(ssize_t&); + /** + * @brief Read and decrypt part of the cdn stream + * + * @param dst buffer where to read received data to + * @param amount of bytes to read + * + * @returns amount of bytes read + */ + long readBytes(uint8_t* dst, size_t bytes); + +#endif /** * @brief Returns current position in CDN stream */ @@ -52,6 +73,8 @@ class CDNAudioFile { */ void seek(size_t position); + long getHeader(); + private: const int OPUS_HEADER_SIZE = 8 * 1024; const int OPUS_FOOTER_PREFFERED = 1024 * 12; // 12K should be safe @@ -60,10 +83,11 @@ class CDNAudioFile { const int HTTP_BUFFER_SIZE = 1024 * 14; const int SPOTIFY_OPUS_HEADER = 167; +#ifndef CONFIG_BELL_NOCODEC // Used to store opus metadata, speeds up read std::vector header = std::vector(OPUS_HEADER_SIZE); std::vector footer; - +#endif // General purpose buffer to read data std::vector httpBuffer = std::vector(HTTP_BUFFER_SIZE); diff --git a/cspot/include/CSpotContext.h b/cspot/include/CSpotContext.h index d4fdde84..aab11ad2 100644 --- a/cspot/include/CSpotContext.h +++ b/cspot/include/CSpotContext.h @@ -2,8 +2,10 @@ #include #include +#include //for random_device and default_random_engine #include "Crypto.h" +#include "EventManager.h" #include "LoginBlob.h" #include "MercurySession.h" #include "TimeProvider.h" @@ -17,6 +19,14 @@ #include "nlohmann/json_fwd.hpp" // for json #endif +#ifdef ESP_PLATFORM +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#define WIFI_CONNECTED_BIT BIT0 +#define WIFI_FAIL_BIT BIT1 +#define CSPOT_CONNECTED_BIT BIT2 +#endif + namespace cspot { struct Context { struct ConfigState { @@ -27,6 +37,10 @@ struct Context { std::vector authData; int volume; +#ifdef ESP_PLATFORM + EventGroupHandle_t s_cspot_event_group; +#endif + std::string username; std::string countryCode; }; @@ -35,6 +49,9 @@ struct Context { std::shared_ptr timeProvider; std::shared_ptr session; + std::shared_ptr playbackMetrics; + std::random_device rd; + std::default_random_engine rng; std::string getCredentialsJson() { #ifdef BELL_ONLY_CJSON cJSON* json_obj = cJSON_CreateObject(); @@ -62,12 +79,20 @@ struct Context { #endif } + void lost_connection(void*) { + //if(!connection) + } + static std::shared_ptr createFromBlob( std::shared_ptr blob) { auto ctx = std::make_shared(); ctx->timeProvider = std::make_shared(); - + ctx->rng = std::default_random_engine{ctx->rd()}; +#ifdef ESP_PLATFORM + //s_cspot_event_group = xEventGroupCreate(); +#endif ctx->session = std::make_shared(ctx->timeProvider); + ctx->playbackMetrics = std::make_shared(ctx); ctx->config.deviceId = blob->getDeviceId(); ctx->config.deviceName = blob->getDeviceName(); ctx->config.authData = blob->authData; diff --git a/cspot/include/ConstantParameters.h b/cspot/include/ConstantParameters.h index 12ebac30..f57bc717 100644 --- a/cspot/include/ConstantParameters.h +++ b/cspot/include/ConstantParameters.h @@ -12,6 +12,6 @@ const char* const brandName = "cspot"; const char* const versionString = "cspot-1.1"; const char* const protocolVersion = "2.7.1"; const char* const defaultDeviceName = "CSpot"; -const char* const swVersion = "1.0.0"; +const char* const swVersion = "1.1.0"; } // namespace cspot \ No newline at end of file diff --git a/cspot/include/DeviceStateHandler.h b/cspot/include/DeviceStateHandler.h new file mode 100644 index 00000000..598e264b --- /dev/null +++ b/cspot/include/DeviceStateHandler.h @@ -0,0 +1,115 @@ +/** + * TO DO + * + * autoplay doesn't work for episodes + * + */ +#pragma once + +#include // for uint8_t, uint32_t +#include //for deque.. +#include //for function +#include // for shared_ptr +#include // for string +#include // for pair +#include // for variant +#include // for vector + +#include "PlayerContext.h" // for PlayerContext::resolveTracklist, jsonToTracklist... +#include "TrackPlayer.h" // for TrackPlayer +#include "TrackQueue.h" +#include "TrackReference.h" +#include "protobuf/connect.pb.h" // for PutStateRequest, DeviceState, PlayerState... + +namespace cspot { +struct Context; +struct PlayerContext; + +class DeviceStateHandler { + public: + //Command Callback Structure + enum CommandType { + STOP, + PLAY, + PAUSE, + DISC, + DEPLETED, + FLUSH, + PLAYBACK_START, + PLAYBACK, + SKIP_NEXT, + SKIP_PREV, + SEEK, + SET_SHUFFLE, + SET_REPEAT, + VOLUME, + TRACK_INFO, + }; + + typedef std::variant, int32_t, bool> + CommandData; + + struct Command { + CommandType commandType; + CommandData data; + }; + + typedef std::function StateCallback; + std::function onClose; + + DeviceStateHandler(std::shared_ptr, std::function); + ~DeviceStateHandler(); + + void disconnect(); + + void putDeviceState(PutStateReason member_type = + PutStateReason::PutStateReason_PLAYER_STATE_CHANGED); + + void setDeviceState(PutStateReason put_state_reason); + void putPlayerState(PutStateReason member_type = + PutStateReason::PutStateReason_PLAYER_STATE_CHANGED); + void handleConnectState(); + void sendCommand(CommandType, CommandData data = {}); + + Device device = Device_init_zero; + + std::vector currentTracks = {}; + StateCallback stateCallback; + + uint64_t started_playing_at = 0; + uint32_t last_message_id = -1; + uint8_t offset = 0; + int64_t offsetFromStartInMillis = 0; + + bool is_active = false; + bool reloadPreloadedTracks = true; + bool needsToBeSkipped = true; + bool playerStateChanged = false; + + std::shared_ptr trackPlayer; + std::shared_ptr trackQueue; + std::shared_ptr ctx; + + private: + std::shared_ptr playerContext; + + std::pair*> queuePacket = { + &offset, ¤tTracks}; + std::vector> metadata_map = {}; + std::vector> context_metadata_map = {}; + std::mutex playerStateMutex; + std::string context_uri, context_url; + void parseCommand(std::vector& data); + void skip(CommandType dir, bool notify); + + void unreference(char** string) { + if (*string != NULL) { + free(*string); + *string = NULL; + } + } + + static void reloadTrackList(void*); + std::atomic resolvingContext = false; +}; +} // namespace cspot \ No newline at end of file diff --git a/cspot/include/EventManager.h b/cspot/include/EventManager.h new file mode 100644 index 00000000..9578045d --- /dev/null +++ b/cspot/include/EventManager.h @@ -0,0 +1,121 @@ +#pragma once + +#include // for uint8_t, uint32_t +#include //for sort +#include // for shared_ptr +#include // for string +#include // for vector + +namespace cspot { +struct Context; +class QueuedTrack; + +struct TrackInterval { + uint64_t start; + uint64_t end; + uint64_t position; + uint64_t length; + + TrackInterval(); + TrackInterval(uint64_t start, uint64_t position) { + this->start = start; + this->position = position; + } +}; + +struct skip { + uint8_t count = 0; + uint64_t amount = 0; + + void add(uint64_t amount) { + this->amount += amount; + count++; + } +}; + +class TrackMetrics { + public: + TrackMetrics(std::shared_ptr ctx, uint64_t pos = 0); + + std::shared_ptr currentInterval; + uint64_t longestInterval = 0, totalAmountOfPlayTime = 0, + totalMsOfPlayedTrack = 0, totalAmountPlayed = 0, audioKeyTime = 0, + trackHeaderTime = 0, written_bytes = 0, track_size = 0, + timestamp = 0, trackLatency = 0; + std::vector> intervals; + skip skipped_backward, skipped_forward; + + void newPosition(uint64_t pos); + void endInterval(uint64_t pos); + void pauseInterval(uint64_t pos, bool pause); + void endTrack(); + void startTrack(); + void startTrackDecoding(); + void startTrackPlaying(uint64_t pos); + uint64_t getPosition(bool paused = false); + + private: + std::shared_ptr ctx; + std::vector> addInterval( + std::vector>& intervals, + std::pair newInterval) { + // Add the new interval to the list of intervals + intervals.push_back(newInterval); + + // Sort intervals by starting time + std::sort(intervals.begin(), intervals.end()); + + // Result vector to hold merged intervals + std::vector> merged; + + // Iterate over intervals to merge overlapping ones + for (const auto& interval : intervals) { + // If merged is empty or current interval does not overlap with the previous one + if (merged.empty() || merged.back().second < interval.first) { + merged.push_back(interval); + } else { + // If it overlaps, merge the intervals + merged.back().second = std::max(merged.back().second, interval.second); + } + } + + return merged; + } +}; +class PlaybackMetrics { + private: + std::shared_ptr ctx; + uint32_t seqNum = 0; + size_t timestamp; + + std::string get_source_from_context(); + std::string get_end_source(); + + void append(std::vector* data, std::string to_do) { + data->insert(data->end(), to_do.begin(), to_do.end()); + data->push_back(9); + } + + public: + PlaybackMetrics(std::shared_ptr ctx) { this->ctx = ctx; } + enum reason { + TRACK_DONE, + TRACK_ERROR, + FORWARD_BTN, + BACKWARD_BTN, + END_PLAY, + PLAY_BTN, + CLICK_ROW, + LOGOUT, + APP_LOAD, + REMOTE, + UNKNOWN + } end_reason = UNKNOWN, + start_reason = UNKNOWN, nested_reason = UNKNOWN; + + std::string context_uri, correlation_id, start_source, end_source; + std::shared_ptr trackMetrics; + + std::vector sendEvent(std::shared_ptr track); +}; +} // namespace cspot \ No newline at end of file diff --git a/cspot/include/MercurySession.h b/cspot/include/MercurySession.h index 91f05f58..d2644ccd 100644 --- a/cspot/include/MercurySession.h +++ b/cspot/include/MercurySession.h @@ -1,20 +1,26 @@ #pragma once -#include // for atomic -#include // for uint8_t, uint64_t, uint32_t +#include // for atomic +#include +#include // for uint8_t, uint64_t, uint32_t +#include #include // for function #include // for shared_ptr #include // for mutex #include // for string #include // for unordered_map #include // for vector +#include "pb_decode.h" #include "BellTask.h" // for Task #include "Packet.h" // for Packet -#include "Queue.h" // for Queue #include "Session.h" // for Session #include "protobuf/mercury.pb.h" // for Header +namespace bell { +class WrappedSemaphore; +}; + namespace cspot { class TimeProvider; @@ -25,14 +31,12 @@ class MercurySession : public bell::Task, public cspot::Session { typedef std::vector> DataParts; struct Response { - Header mercuryHeader; - uint8_t flags; + Header mercuryHeader = Header_init_default; DataParts parts; uint64_t sequenceId; - bool fail; + bool fail = true; }; - - typedef std::function ResponseCallback; + typedef std::function ResponseCallback; typedef std::function&)> AudioKeyCallback; typedef std::function ConnectionEstabilishedCallback; @@ -42,7 +46,9 @@ class MercurySession : public bell::Task, public cspot::Session { UNSUB = 0xb4, SUBRES = 0xb5, SEND = 0xb2, - GET = 0xFF, // Shitty workaround, it's value is actually same as SEND + GET = 0xFF, // Shitty workaround, it's value is actually same as SEND + POST = 0xb6, //?? + PUT = 0xb7, //?? PING = 0x04, PONG_ACK = 0x4a, AUDIO_CHUNK_REQUEST_COMMAND = 0x08, @@ -54,15 +60,22 @@ class MercurySession : public bell::Task, public cspot::Session { COUNTRY_CODE_RESPONSE = 0x1B, }; + enum class ResponseFlag : uint8_t { + FINAL = 0x01, + PARTIAL = 0x02, + }; + std::unordered_map RequestTypeMap = { - {RequestType::GET, "GET"}, - {RequestType::SEND, "SEND"}, - {RequestType::SUB, "SUB"}, - {RequestType::UNSUB, "UNSUB"}, + {RequestType::GET, "GET"}, {RequestType::SEND, "SEND"}, + {RequestType::SUB, "SUB"}, {RequestType::UNSUB, "UNSUB"}, + {RequestType::POST, "POST"}, {RequestType::PUT, "PUT"}, }; void handlePacket(); + void addSubscriptionListener(const std::string& uri, + ResponseCallback subscription); + uint64_t executeSubscription(RequestType type, const std::string& uri, ResponseCallback callback, ResponseCallback subscription, DataParts& parts); @@ -98,6 +111,8 @@ class MercurySession : public bell::Task, public cspot::Session { void setConnectedHandler(ConnectionEstabilishedCallback callback); bool triggerTimeout() override; + bool isReconnecting = false; + void reconnect(); private: const int PING_TIMEOUT_MS = 2 * 60 * 1000 + 5000; @@ -106,14 +121,14 @@ class MercurySession : public bell::Task, public cspot::Session { Header tempMercuryHeader = {}; ConnectionEstabilishedCallback connectionReadyCallback = nullptr; - bell::Queue packetQueue; + std::deque packetQueue; void runTask() override; - void reconnect(); - std::unordered_map callbacks; + std::deque partials; std::unordered_map subscriptions; std::unordered_map audioKeyCallbacks; + std::shared_ptr responseSemaphore; uint64_t sequenceId = 1; uint32_t audioKeySequence = 1; @@ -122,13 +137,20 @@ class MercurySession : public bell::Task, public cspot::Session { unsigned long long lastPingTimestamp = -1; std::string countryCode = ""; + std::mutex queueMutex; std::mutex isRunningMutex; + std::condition_variable queueCV; // For synchronization with waits std::atomic isRunning = false; - std::atomic isReconnecting = false; std::atomic executeEstabilishedCallback = false; + std::atomic connection_lost = false; void failAllPending(); - Response decodeResponse(const std::vector& data); + void handleReconnection(); + bool processPackets(); + MercurySession::Response decodeResponse(const std::vector& data); + std::vector prepareSequenceIdPayload( + uint64_t sequenceId, const std::vector& headerBytes, + const DataParts& payload); }; -} // namespace cspot +} // namespace cspot \ No newline at end of file diff --git a/cspot/include/PlaybackState.h b/cspot/include/PlaybackState.h deleted file mode 100644 index a79eab01..00000000 --- a/cspot/include/PlaybackState.h +++ /dev/null @@ -1,97 +0,0 @@ -#pragma once - -#include // for uint8_t, uint32_t -#include // for shared_ptr -#include // for string -#include // for vector - -#include "TrackReference.h" -#include "protobuf/spirc.pb.h" // for Frame, TrackRef, CapabilityType, Mess... - -namespace cspot { -struct Context; - -class PlaybackState { - private: - std::shared_ptr ctx; - - uint32_t seqNum = 0; - uint8_t capabilityIndex = 0; - - std::vector frameData; - - void addCapability( - CapabilityType typ, int intValue = -1, - std::vector stringsValue = std::vector()); - - public: - Frame innerFrame; - Frame remoteFrame; - - std::vector remoteTracks; - - enum class State { Playing, Stopped, Loading, Paused }; - - /** - * @brief Player state represents the current state of player. - * - * Responsible for keeping track of player's state. Doesn't control the playback itself. - * - * @param timeProvider synced time provider - */ - PlaybackState(std::shared_ptr ctx); - - ~PlaybackState(); - - /** - * @brief Updates state according to current playback state. - * - * @param state playback state - */ - void setPlaybackState(const PlaybackState::State state); - - /** - * @brief Sets player activity - * - * @param isActive activity status - */ - void setActive(bool isActive); - - /** - * @brief Simple getter - * - * @return true player is active - * @return false player is inactive - */ - bool isActive(); - - /** - * @brief Updates local track position. - * - * @param position position in milliseconds - */ - void updatePositionMs(uint32_t position); - - /** - * @brief Sets local volume on internal state. - * - * @param volume volume between 0 and UINT16 max - */ - void setVolume(uint32_t volume); - - /** - * @brief Updates local track queue from remote data. - */ - void syncWithRemote(); - - /** - * @brief Encodes current frame into binary data via protobuf. - * - * @param typ message type to include in frame type - * @return std::vector binary frame data - */ - std::vector encodeCurrentFrame(MessageType typ); - - bool decodeRemoteFrame(std::vector& data); -}; -} // namespace cspot diff --git a/cspot/include/PlayerContext.h b/cspot/include/PlayerContext.h new file mode 100644 index 00000000..733f34c7 --- /dev/null +++ b/cspot/include/PlayerContext.h @@ -0,0 +1,68 @@ +#ifndef PLAYER_CONTEXT_H +#define PLAYER_CONTEXT_H + +#include +#include // for shared_ptr +#include //for scoped_loc, mutex... +#include +#include //for random_device and default_random_engine +#include // for pair +#include //for vector + +#include "BellTask.h" +#include "CSpotContext.h" +#include "TrackReference.h" //for TrackReference +#include "nlohmann/json.hpp" // for basic_json<>::object_t, basic_json +#include "nlohmann/json_fwd.hpp" // for json + +#include "protobuf/metadata.pb.h" // for Track, _Track, AudioFile, Episode +#define MAX_TRACKS 100 +namespace cspot { +struct PlayerContext { + PlayerContext(std::shared_ptr ctx, PlayerState* playerState, + std::vector* tracks, uint8_t* index) { + this->ctx = ctx; + this->playerState = playerState; + this->tracks = tracks; + this->index = index; + } + void autoplayQuery( + std::vector> metadata_map, + void (*responseFunction)(void*), bool secondTry = false); + void resolveRadio( + std::vector> metadata_map, + void (*responseFunction)(void*), char*); + + void resolveTracklist( + std::vector> metadata_map, + void (*responseFunction)(void*), bool state_changed = false, + bool trackIsPartOfContext = false); + uint8_t jsonToTracklist( + std::vector* tracks, + std::vector> metadata_map, + nlohmann::json::value_type& json_tracks, const char* provider, + uint32_t offset = 0, uint8_t page = 0, bool shuffle = false, + bool preloadedTrack = false); + void createIndexBasedOnTracklist(std::vector* tracks, + nlohmann::json::value_type& json_tracks, + bool shuffle, uint8_t page); + //void jsonToPlayerStateContext(PlayerState* playerState, std::vector* tracks, uint8_t* index, std::vector> metadata_map,nlohmann::json::object_t context); + static char* createStringReferenceIfFound( + nlohmann::json::value_type& jsonObject, const char* key); + uint64_t radio_offset = 0; + std::mutex trackListMutex; + std::shared_ptr ctx; + PlayerState* playerState; + std::vector* tracks; + uint8_t* index; + std::vector alternative_index; + char* next_page_url = NULL; + std::string context_uri; + ~PlayerContext() { + if (next_page_url != NULL) + free(next_page_url); + } +}; +}; // namespace cspot + +#endif \ No newline at end of file diff --git a/cspot/include/Session.h b/cspot/include/Session.h index df7f03c8..4962e5b3 100644 --- a/cspot/include/Session.h +++ b/cspot/include/Session.h @@ -23,7 +23,7 @@ class Session { std::shared_ptr conn; std::shared_ptr authBlob; - std::string deviceId = "142137fd329622137a14901634264e6f332e2411"; + //std::string deviceId = "142137fd329622137a14901634264e6f332e2411"; public: Session(); diff --git a/cspot/include/SpircHandler.h b/cspot/include/SpircHandler.h deleted file mode 100644 index 7d558cd8..00000000 --- a/cspot/include/SpircHandler.h +++ /dev/null @@ -1,82 +0,0 @@ -#pragma once - -#include // for uint32_t, uint8_t -#include // for function -#include // for shared_ptr, unique_ptr -#include // for string -#include // for variant -#include // for vector - -#include "CDNAudioFile.h" // for CDNTrackStream, CDNTrackStream::Track... -#include "TrackQueue.h" -#include "protobuf/spirc.pb.h" // for MessageType - -namespace cspot { -class TrackPlayer; -struct Context; - -class SpircHandler { - public: - SpircHandler(std::shared_ptr ctx); - - enum class EventType { - PLAY_PAUSE, - VOLUME, - TRACK_INFO, - DISC, - NEXT, - PREV, - SEEK, - DEPLETED, - FLUSH, - PLAYBACK_START - }; - - typedef std::variant EventData; - - struct Event { - EventType eventType; - EventData data; - }; - - typedef std::function)> EventHandler; - - void subscribeToMercury(); - std::shared_ptr getTrackPlayer(); - - void setEventHandler(EventHandler handler); - - void setPause(bool pause); - - bool previousSong(); - - bool nextSong(); - - void notifyAudioReachedPlayback(); - void notifyAudioEnded(); - void updatePositionMs(uint32_t position); - void setRemoteVolume(int volume); - void loadTrackFromURI(const std::string& uri); - std::shared_ptr getTrackQueue() { return trackQueue; } - - void disconnect(); - - private: - std::shared_ptr ctx; - std::shared_ptr trackPlayer; - std::shared_ptr trackQueue; - - EventHandler eventHandler = nullptr; - - std::shared_ptr playbackState; - - void sendCmd(MessageType typ); - - void sendEvent(EventType type); - void sendEvent(EventType type, EventData data); - - bool skipSong(TrackQueue::SkipDirection dir); - void handleFrame(std::vector& data); - void notify(); -}; -} // namespace cspot diff --git a/cspot/include/TrackPlayer.h b/cspot/include/TrackPlayer.h index 1577c476..8a63d651 100644 --- a/cspot/include/TrackPlayer.h +++ b/cspot/include/TrackPlayer.h @@ -17,11 +17,13 @@ namespace bell { class WrappedSemaphore; } // namespace bell +#ifndef CONFIG_BELL_NOCODEC #ifdef BELL_VORBIS_FLOAT #include "vorbis/vorbisfile.h" #else #include "ivorbisfile.h" // for OggVorbis_File, ov_callbacks #endif +#endif namespace cspot { class TrackProvider; @@ -33,29 +35,35 @@ class TrackPlayer : bell::Task { public: // Callback types typedef std::function, bool)> - TrackLoadedCallback; - typedef std::function - DataCallback; - typedef std::function EOFCallback; + TrackChangedCallback; + typedef std::function DataCallback; + typedef std::function TrackEndedCallback; + typedef std::function SeekableCallback; + TrackEndedCallback onTrackEnd; TrackPlayer(std::shared_ptr ctx, std::shared_ptr trackQueue, - EOFCallback eofCallback, TrackLoadedCallback loadedCallback); + TrackEndedCallback onTrackEnd, + TrackChangedCallback onTrackChanged, bool* track_repeat); ~TrackPlayer(); void loadTrackFromRef(TrackReference& ref, size_t playbackMs, bool startAutomatically); - void setDataCallback(DataCallback callback); + void setDataCallback(DataCallback callback, + SeekableCallback seekable_callback = nullptr, + SeekableCallback spaces_available = nullptr); // CDNTrackStream::TrackInfo getCurrentTrackInfo(); - void seekMs(size_t ms); + void seekMs(size_t ms, bool loading = true); void resetState(bool paused = false); +#ifndef CONFIG_BELL_NOCODEC // Vorbis codec callbacks size_t _vorbisRead(void* ptr, size_t size, size_t nmemb); size_t _vorbisClose(); int _vorbisSeek(int64_t offset, int whence); long _vorbisTell(); +#endif void stop(); void start(); @@ -67,19 +75,26 @@ class TrackPlayer : bell::Task { std::unique_ptr playbackSemaphore; - TrackLoadedCallback trackLoaded; + TrackChangedCallback onTrackChanged; DataCallback dataCallback = nullptr; - EOFCallback eofCallback; +#ifdef CONFIG_BELL_NOCODEC + SeekableCallback spaces_available = nullptr; + SeekableCallback seekable_callback; + size_t seekable_offset; +#endif // Playback control std::atomic currentSongPlaying; + bool* repeating_track_; std::mutex playbackMutex; std::mutex dataOutMutex; +#ifndef CONFIG_BELL_NOCODEC // Vorbis related OggVorbis_File vorbisFile; ov_callbacks vorbisCallbacks; int currentSection; +#endif std::vector pcmBuffer = std::vector(1024); diff --git a/cspot/include/TrackQueue.h b/cspot/include/TrackQueue.h index 8e2f0c37..f021829d 100644 --- a/cspot/include/TrackQueue.h +++ b/cspot/include/TrackQueue.h @@ -5,11 +5,14 @@ #include #include #include +#include // for pair #include "BellTask.h" -#include "PlaybackState.h" +#include "EventManager.h" // for TrackMetrics #include "TrackReference.h" +#include "Utils.h" +#include "protobuf/connect.pb.h" // for ProvidedTrack #include "protobuf/metadata.pb.h" // for Track, _Track, AudioFile, Episode namespace bell { @@ -32,8 +35,9 @@ struct TrackInfo { class QueuedTrack { public: - QueuedTrack(TrackReference& ref, std::shared_ptr ctx, - uint32_t requestedPosition = 0); + QueuedTrack(ProvidedTrack& ref, std::shared_ptr ctx, + std::shared_ptr playableSemaphore, + int64_t requestedPosition = 0); ~QueuedTrack(); enum class State { @@ -49,12 +53,22 @@ class QueuedTrack { std::shared_ptr loadedSemaphore; State state = State::QUEUED; // Current state of the track - TrackReference ref; // Holds GID, URI and Context TrackInfo trackInfo; // Full track information fetched from spotify, name etc - - uint32_t requestedPosition; + ProvidedTrack ref; std::string identifier; + uint32_t playingTrackIndex; + uint32_t requestedPosition; + AudioFormat audioFormat; bool loading = false; + uint8_t retries = 0; + + // PB data + Track pbTrack = Track_init_zero; + Episode pbEpisode = Episode_init_zero; + + // EventManager data + int64_t written_bytes = 0; + std::shared_ptr trackMetrics; // Will return nullptr if the track is not ready std::shared_ptr getAudioFile(); @@ -72,63 +86,50 @@ class QueuedTrack { void stepLoadCDNUrl(const std::string& accessKey); - void expire(); - private: std::shared_ptr ctx; + std::shared_ptr playableSemaphore; uint64_t pendingMercuryRequest = 0; uint32_t pendingAudioKeyRequest = 0; std::vector trackId, fileId, audioKey; std::string cdnUrl; + std::pair> gid = { + SpotifyFileType::UNKNOWN, + {}}; }; class TrackQueue : public bell::Task { public: - TrackQueue(std::shared_ptr ctx, - std::shared_ptr playbackState); + TrackQueue(std::shared_ptr ctx); ~TrackQueue(); enum class SkipDirection { NEXT, PREV }; std::shared_ptr playableSemaphore; + std::shared_ptr accessKeyFetcher; std::atomic notifyPending = false; + std::deque> preloadedTracks; + bool repeat = false; void runTask() override; void stopTask(); - bool hasTracks(); - bool isFinished(); - bool skipTrack(SkipDirection dir, bool expectNotify = true); - bool updateTracks(uint32_t requestedPosition = 0, bool initial = false); + bool skipTrack(SkipDirection dir, bool expectNotify = false); TrackInfo getTrackInfo(std::string_view identifier); std::shared_ptr consumeTrack( std::shared_ptr prevSong, int& offset); + std::mutex tracksMutex, runningMutex; private: - static const int MAX_TRACKS_PRELOAD = 3; - - std::shared_ptr accessKeyFetcher; - std::shared_ptr playbackState; std::shared_ptr ctx; std::shared_ptr processSemaphore; - std::deque> preloadedTracks; - std::vector currentTracks; - std::mutex tracksMutex, runningMutex; - - // PB data - Track pbTrack; - Episode pbEpisode; + std::atomic isRunning = false; std::string accessKey; - int16_t currentTracksIndex = -1; - - bool isRunning = false; - - void processTrack(std::shared_ptr track); - bool queueNextTrack(int offset = 0, uint32_t positionMs = 0); + bool processTrack(std::shared_ptr track); }; -} // namespace cspot +} // namespace cspot \ No newline at end of file diff --git a/cspot/include/TrackReference.h b/cspot/include/TrackReference.h index 8b986349..17e6a1cb 100644 --- a/cspot/include/TrackReference.h +++ b/cspot/include/TrackReference.h @@ -5,12 +5,28 @@ #include #include #include "NanoPBHelper.h" +#include "Utils.h" //for base62decode #include "pb_decode.h" -#include "protobuf/spirc.pb.h" +#include "protobuf/connect.pb.h" + +#define TRACK_SEND_LIMIT 15 namespace cspot { struct TrackReference { TrackReference(); + TrackReference(std::string uri, std::string context) : type(Type::TRACK) { + this->gid = base62Decode(uri).second; + //this->uri=uri; + this->context = context; + } + TrackReference(std::string uri) : type(Type::TRACK) { + gid = base62Decode(uri).second; + + if (uri.find("episode:") != std::string::npos) { + type = Type::EPISODE; + } + this->uri = uri; + } // Resolved track GID std::vector gid; @@ -22,15 +38,40 @@ struct TrackReference { Type type; - void decodeURI(); - bool operator==(const TrackReference& other) const; // Encodes list of track references into a pb structure, used by nanopb - static bool pbEncodeTrackList(pb_ostream_t* stream, const pb_field_t* field, - void* const* arg); + static bool pbEncodeProvidedTracks(pb_ostream_t* stream, + const pb_field_t* field, void* const* arg); + + static bool pbDecodeProvidedTracks(pb_istream_t* stream, + const pb_field_t* field, void** arg); + + static void clearProvidedTracklist(std::vector* tracklist) { + for (auto& track : *tracklist) + pbReleaseProvidedTrack(&track); + tracklist->clear(); + } + + static void deleteTracksInRange(std::vector* tracks, + size_t start, size_t end) { + // Sanity check for the range bounds + if (start >= tracks->size() || end >= tracks->size() || start > end) { + return; // Invalid range + } + + // Release resources for each track in the specified range + for (size_t i = start; i <= end; ++i) + pbReleaseProvidedTrack(&tracks->at(i)); + + // Erase the range of tracks from the tracklist + tracks->erase(tracks->begin() + start, tracks->begin() + end + 1); + } - static bool pbDecodeTrackList(pb_istream_t* stream, const pb_field_t* field, - void** arg); + static void pbReleaseProvidedTrack(ProvidedTrack* track) { + if (track->metadata_count < track->full_metadata_count) + track->metadata_count = track->full_metadata_count; + pb_release(ProvidedTrack_fields, track); + } }; } // namespace cspot diff --git a/cspot/include/Utils.h b/cspot/include/Utils.h index a52be4ea..e2ce70ca 100644 --- a/cspot/include/Utils.h +++ b/cspot/include/Utils.h @@ -15,8 +15,10 @@ #include // for unique_ptr #include // for runtime_error #include // for string +#include // for pair #define HMAC_SHA1_BLOCKSIZE 64 +enum class SpotifyFileType { TRACK, EPISODE, UNKNOWN }; /** * @brief Returns current timestamp @@ -33,6 +35,14 @@ unsigned long long getCurrentTimestamp(); */ uint64_t hton64(uint64_t value); +/** + * @brief Encodes a bytestream to a base64 string + * + * @param v std::vector + * @return std::string + */ +std::string base64Encode(const std::vector& v); + std::vector bigNumDivide(std::vector num, int n); /** @@ -55,6 +65,14 @@ std::vector bigNumAdd(std::vector num, int n); unsigned char h2int(char c); +/** + * @brief Extracts the spotify id from a spotify uri and decodes its base62-format + * + * @param uri spotify uri/spotify id(base62) string + * @return std::vector gid + */ +std::pair> base62Decode(std::string uri); + std::string urlDecode(std::string str); /** diff --git a/cspot/protobuf/connect.options b/cspot/protobuf/connect.options new file mode 100644 index 00000000..3c8ba150 --- /dev/null +++ b/cspot/protobuf/connect.options @@ -0,0 +1,76 @@ +DeviceInfo.name type:FT_POINTER +DeviceInfo.device_id type:FT_POINTER +DeviceInfo.client_id type:FT_POINTER +DeviceInfo.spirc_version type:FT_POINTER +//DeviceInfo.supported_types type:FT_POINTER +DeviceInfo.device_software_version type:FT_POINTER +DeviceInfo.model type:FT_POINTER +DeviceInfo.brand type:FT_POINTER +PutStateRequest.callback_url type:FT_POINTER +PutStateRequest.last_command_sent_by_device_id type:FT_POINTER +Capabilities.supported_types type:FT_POINTER +Capabilities.supported_typesEntry type:FT_POINTER +Cluster.device max_count:10 fixed_count:false +Cluster.DeviceEntry.key type:FT_POINTER +Cluster.active_device_id type:FT_POINTER +ProvidedTrack.uri type:FT_POINTER +ProvidedTrack.uid type:FT_POINTER +ProvidedTrack.metadata max_count:30, fixed_count:false +ProvidedTrack.MetadataEntry type:FT_POINTER +ProvidedTrack.removed type:FT_POINTER +ProvidedTrack.blocked type:FT_POINTER +ProvidedTrack.provider type:FT_POINTER +ProvidedTrack.album_uri type:FT_POINTER +ProvidedTrack.disallow_reasons type:FT_POINTER +ProvidedTrack.artist_uri type:FT_POINTER +ProvidedTrack.disallow_undecided type:FT_POINTER +PlayOrigin.feature_identifier type:FT_POINTER +PlayOrigin.feature_version type:FT_POINTER +PlayOrigin.view_uri type:FT_POINTER +PlayOrigin.external_referrer type:FT_POINTER +PlayOrigin.referrer_identifier type:FT_POINTER +PlayOrigin.device_identifier type:FT_POINTER +PlayOrigin.feature_classes type:FT_POINTER +PlayerState.playback_id type:FT_POINTER + +ContextPlayerOptions.context_enhancement max_count:2, fixed_count:false +ContextPlayerOptions.ContextEnhancementEntry type:FT_POINTER + +Restrictions type:FT_POINTER + +PlayerState.context_uri type:FT_POINTER +PlayerState.context_url type:FT_POINTER +PlayerState.context_metadata type:FT_POINTER +PlayerState.ContextMetadataEntry type:FT_POINTER +PlayerState.page_metadata type:FT_POINTER +PlayerState.PageMetadataEntry type:FT_POINTER +PlayerState.session_id type:FT_POINTER +PlayerState.queue_revision type:FT_POINTER +PlayerState.entity_uri type:FT_POINTER +PlayerState.playback_provider type:FT_POINTER +PlayerState.random_message type:FT_POINTER + +Restrictions.disallow_pausing_reasons type:FT_POINTER +Restrictions.disallow_resuming_reasons type:FT_POINTER +Restrictions.disallow_seeking_reasons type:FT_POINTER +Restrictions.disallow_peeking_prev_reasons type:FT_POINTER +Restrictions.disallow_peeking_next_reasons type:FT_POINTER +Restrictions.disallow_skipping_prev_reasons type:FT_POINTER +Restrictions.disallow_skipping_next_reasons type:FT_POINTER +Restrictions.disallow_toggling_repeat_context_reasons type:FT_POINTER +Restrictions.disallow_toggling_repeat_track_reasons type:FT_POINTER +Restrictions.disallow_toggling_shuffle_reasons type:FT_POINTER +Restrictions.disallow_set_queue_reasons type:FT_POINTER +Restrictions.disallow_interrupting_playback_reasons type:FT_POINTER +Restrictions.disallow_transferring_playback_reasons type:FT_POINTER +Restrictions.disallow_remote_control_reasons type:FT_POINTER +Restrictions.disallow_inserting_into_next_tracks_reasons type:FT_POINTER +Restrictions.disallow_inserting_into_context_tracks_reasons type:FT_POINTER +Restrictions.disallow_reordering_in_next_tracks_reasons type:FT_POINTER +Restrictions.disallow_reordering_in_context_tracks_reasons type:FT_POINTER +Restrictions.disallow_removing_from_next_tracks_reasons type:FT_POINTER +Restrictions.disallow_removing_from_context_tracks_reasons type:FT_POINTER +Restrictions.disallow_updating_context_reasons type:FT_POINTER +Restrictions.disallow_playing_reasons type:FT_POINTER +Restrictions.disallow_stopping_reasons type:FT_POINTER +Restrictions.disallow_loading_context_reasons type:FT_POINTER \ No newline at end of file diff --git a/cspot/protobuf/connect.proto b/cspot/protobuf/connect.proto new file mode 100644 index 00000000..c27b843f --- /dev/null +++ b/cspot/protobuf/connect.proto @@ -0,0 +1,345 @@ +syntax = "proto2"; + +message PlayerState { + optional int64 timestamp = 1; + optional string context_uri = 2; + optional string context_url = 3; + optional Restrictions context_restrictions = 4; + optional PlayOrigin play_origin = 5; + optional ContextIndex index = 6; + optional ProvidedTrack track = 7; + optional string playback_id = 8; + optional double playback_speed = 9; + optional int64 position_as_of_timestamp = 10; + optional int64 duration = 11; + optional bool is_playing = 12; + optional bool is_paused = 13; + optional bool is_buffering = 14; + optional bool is_system_initiated = 15; + optional ContextPlayerOptions options = 16; + optional Restrictions restrictions = 17; + optional Suppressions suppressions = 18; + repeated ProvidedTrack prev_tracks = 19; + repeated ProvidedTrack next_tracks = 20; + map context_metadata = 21; + map page_metadata = 22; + optional string session_id = 23; + optional string queue_revision = 24; + optional int64 position = 25; + optional string entity_uri = 26; + repeated ProvidedTrack reverse = 27; + repeated ProvidedTrack future = 28; + optional PlaybackQuality playback_quality = 32; + optional string playback_provider = 33; + optional string random_message = 35; +} + +message ProvidedTrack { + optional string uri = 1; + optional string uid = 2; + map metadata = 3; + optional string removed = 4; + repeated string blocked = 5; + optional string provider = 6; + optional Restrictions restrictions = 7; + optional string album_uri = 8; + repeated string disallow_reasons = 9; + optional string artist_uri = 10; + repeated string disallow_undecided = 11; + optional uint32 page = 253; + optional uint32 original_index = 254; + optional uint32 full_metadata_count = 255; +} + +message ContextIndex { + optional uint32 page = 1; + optional uint32 track = 2; +} + +message Restrictions { + repeated string disallow_pausing_reasons = 1; + repeated string disallow_resuming_reasons = 2; + repeated string disallow_seeking_reasons = 3; + repeated string disallow_peeking_prev_reasons = 4; + repeated string disallow_peeking_next_reasons = 5; + repeated string disallow_skipping_prev_reasons = 6; + repeated string disallow_skipping_next_reasons = 7; + repeated string disallow_toggling_repeat_context_reasons = 8; + repeated string disallow_toggling_repeat_track_reasons = 9; + repeated string disallow_toggling_shuffle_reasons = 10; + repeated string disallow_set_queue_reasons = 11; + repeated string disallow_interrupting_playback_reasons = 12; + repeated string disallow_transferring_playback_reasons = 13; + repeated string disallow_remote_control_reasons = 14; + repeated string disallow_inserting_into_next_tracks_reasons = 15; + repeated string disallow_inserting_into_context_tracks_reasons = 16; + repeated string disallow_reordering_in_next_tracks_reasons = 17; + repeated string disallow_reordering_in_context_tracks_reasons = 18; + repeated string disallow_removing_from_next_tracks_reasons = 19; + repeated string disallow_removing_from_context_tracks_reasons = 20; + repeated string disallow_updating_context_reasons = 21; + repeated string disallow_playing_reasons = 22; + repeated string disallow_stopping_reasons = 23; + repeated string disallow_loading_context_reasons = 25; +} + +message PlayOrigin { + optional string feature_identifier = 1; + optional string feature_version = 2; + optional string view_uri = 3; + optional string external_referrer = 4; + optional string referrer_identifier = 5; + optional string device_identifier = 6; + optional string feature_classes = 7; +} + +message ContextEnhancement{ + optional string key = 1; + optional string value = 2; +} + +message ContextPlayerOptions { + optional bool shuffling_context = 1; + optional bool repeating_context = 2; + optional bool repeating_track = 3; + + map context_enhancement = 5; +} + +message Suppressions { + repeated string providers = 1; +} + +enum BitrateLevel { + unknown = 0; + low = 1; + normal = 2; + high = 3; + veryhigh = 4; + normalized = 5; +} + +enum BitrateStrategy { + unknown_strategy = 0; + best_matching = 1; + backend_advised = 2; + offlined_file = 3; + cached_file = 4; + local_file = 5; +} + +enum HiFiStatus { + none = 0; + off = 1; + on = 2; +} + +message PlaybackQuality { + optional BitrateLevel bitrate_level = 1; + optional BitrateStrategy strategy = 2; + optional BitrateLevel target_bitrate_level = 3; + optional bool target_bitrate_available = 4; + optional HiFiStatus hifi_status = 5; +} + +message ClusterUpdate { + optional Cluster cluster = 1; + optional ClusterUpdateReason update_reason = 2; + optional string ack_id = 3; + repeated string devices_that_changed = 4; +} + +message Device { + optional DeviceInfo device_info = 1; + optional PlayerState player_state = 2; + optional PrivateDeviceInfo private_device_info = 3; + optional bytes transfer_data = 4; // TransferState +} + +message Cluster { + optional uint64 timestamp = 1; + optional string active_device_id = 2; + optional PlayerState player_state = 3; + map device = 4; + optional bytes transfer_data = 5; + optional uint64 transfer_data_timestamp = 6; + optional int64 not_playing_since_timestamp = 7; + optional bool need_full_player_state = 8; + optional int64 server_timestamp_ms = 9; +} + +message PutStateRequest { + optional string callback_url = 1; + optional Device device = 2; + optional MemberType member_type = 3; + optional bool is_active = 4; + optional PutStateReason put_state_reason = 5; + optional uint32 message_id = 6; + optional string last_command_sent_by_device_id = 7; + optional uint32 last_command_message_id = 8; + optional uint64 started_playing_at = 9; + optional uint64 has_been_playing_for_ms = 11; + optional uint64 client_side_timestamp = 12; + optional bool only_write_player_state = 13; +} + +message PrivateDeviceInfo { + optional string platform = 1; +} + +message SubscribeRequest { + optional string callback_url = 1; +} + +message DeviceInfo { + message DeviceAliasesEntry { + optional uint32 key = 1; + optional DeviceAlias value = 2; + } + optional bool can_play = 1; + optional uint32 volume = 2; + optional string name = 3; + optional Capabilities capabilities = 4; + optional string device_software_version = 6; + optional DeviceType device_type = 7; + optional string spirc_version = 9; + optional string device_id = 10; + optional bool is_private_session = 11; + optional bool is_social_connect = 12; + optional string client_id = 13; + optional string brand = 14; + optional string model = 15; + map metadata_map = 16; + optional string product_id = 17; + optional string deduplication_id = 18; + optional uint32 selected_alias_id = 19; + repeated DeviceAliasesEntry device_aliases = 20; + optional bool is_offline = 21; + optional string public_ip = 22; + optional string license = 23; +} + +message DeviceAlias { + optional uint32 id = 1; + optional string name = 2; + optional bool is_group = 3; +} + +message Capabilities { + optional bool can_be_player = 2; + optional bool restrict_to_local = 3; + optional bool gaia_eq_connect_id = 5; + optional bool supports_logout = 6; + optional bool is_observable = 7; + optional int32 volume_steps = 8; + repeated string supported_types = 9; + optional bool command_acks = 10; + optional bool supports_rename = 11; + optional bool hidden = 12; + optional bool disable_volume = 13; + optional bool connect_disabled = 14; + optional bool supports_playlist_v2 = 15; + optional bool is_controllable = 16; + optional bool supports_external_episodes = 17; + optional bool supports_set_backend_metadata = 18; + optional bool supports_transfer_command = 19; + optional bool supports_command_request = 20; + optional bool is_voice_enabled = 21; + optional bool needs_full_player_state = 22; + optional bool supports_gzip_pushes = 23; + optional bool supports_lossless_audio = 24; + optional bool supports_set_options_command = 25; + optional CapabilitySupportDetails supports_hifi = 26; + // reserved 1, "supported_contexts"; +} + +message CapabilitySupportDetails { + optional bool fully_supported = 1; + optional bool user_eligible = 2; + optional bool device_supported = 3; +} + +message ConnectCommandOptions { + optional int32 message_id = 1; +} + +message LogoutCommand { + optional ConnectCommandOptions command_options = 1; +} + +message SetVolumeCommand { + optional int32 volume = 1; + optional ConnectCommandOptions command_options = 2; +} + +message RenameCommand { + optional string rename_to = 1; + optional ConnectCommandOptions command_options = 2; +} + +message SetBackendMetadataCommand { + map metadata = 1; +} + +enum SendCommandResult { + UNKNOWN_SEND_COMMAND_RESULT = 0; + SUCCESS = 1; + DEVICE_NOT_FOUND = 2; + CONTEXT_PLAYER_ERROR = 3; + DEVICE_DISAPPEARED = 4; + UPSTREAM_ERROR = 5; + DEVICE_DOES_NOT_SUPPORT_COMMAND = 6; + RATE_LIMITED = 7; +} + +enum PutStateReason { + UNKNOWN_PUT_STATE_REASON = 0; + SPIRC_HELLO = 1; + SPIRC_NOTIFY = 2; + NEW_DEVICE = 3; + PLAYER_STATE_CHANGED = 4; + VOLUME_CHANGED = 5; + PICKER_OPENED = 6; + BECAME_INACTIVE = 7; + ALIAS_CHANGED = 8; +} + +enum MemberType { + SPIRC_V2 = 0; + SPIRC_V3 = 1; + CONNECT_STATE = 2; + CONNECT_STATE_EXTENDED = 5; + ACTIVE_DEVICE_TRACKER = 6; + PLAY_TOKEN = 7; +} + +enum ClusterUpdateReason { + UNKNOWN_CLUSTER_UPDATE_REASON = 0; + DEVICES_DISAPPEARED = 1; + DEVICE_STATE_CHANGED = 2; + NEW_DEVICE_APPEARED = 3; + DEVICE_VOLUME_CHANGED = 4; + DEVICE_ALIAS_CHANGED = 5; +} + +enum DeviceType { + UNKNOWN = 0; + COMPUTER = 1; + TABLET = 2; + SMARTPHONE = 3; + SPEAKER = 4; + TV = 5; + AVR = 6; + STB = 7; + AUDIO_DONGLE = 8; + GAME_CONSOLE = 9; + CAST_VIDEO = 10; + CAST_AUDIO = 11; + AUTOMOBILE = 12; + SMARTWATCH = 13; + CHROMEBOOK = 14; + UNKNOWN_SPOTIFY = 100; + CAR_THING = 101; + OBSERVER = 102; + HOME_THING = 103; +} diff --git a/cspot/protobuf/mercury.options b/cspot/protobuf/mercury.options index e7c7718b..071a17b9 100644 --- a/cspot/protobuf/mercury.options +++ b/cspot/protobuf/mercury.options @@ -1,2 +1,5 @@ -Header.uri max_size:256, fixed_length:false -Header.method max_size:64, fixed_length:false +Header.uri type:FT_POINTER +Header.method type:FT_POINTER +UserField.key type:FT_POINTER +UserField.value type:FT_POINTER +Header.user_fields max_count:10, fixed_count:false \ No newline at end of file diff --git a/cspot/protobuf/mercury.proto b/cspot/protobuf/mercury.proto index 72138948..cd754d2d 100644 --- a/cspot/protobuf/mercury.proto +++ b/cspot/protobuf/mercury.proto @@ -1,4 +1,12 @@ message Header { optional string uri = 0x01; + optional string content_type = 0x02; optional string method = 0x03; + optional int32 status_code = 0x04; + repeated UserField user_fields = 0x06; } + +message UserField { + optional string key = 0x01; + optional string value = 0x02; +} \ No newline at end of file diff --git a/cspot/protobuf/spirc.options b/cspot/protobuf/spirc.options index b7331f53..1804712a 100644 --- a/cspot/protobuf/spirc.options +++ b/cspot/protobuf/spirc.options @@ -7,4 +7,6 @@ DeviceState.sw_version type:FT_POINTER DeviceState.name type:FT_POINTER DeviceState.capabilities max_count:17, fixed_count:false State.context_uri type:FT_POINTER +State.last_command_ident type:FT_POINTER +State.context_description type:FT_POINTER TrackRef.queued type:FT_CALLBACK \ No newline at end of file diff --git a/cspot/protobuf/spirc.proto b/cspot/protobuf/spirc.proto index 5d54bd26..fcd3a512 100644 --- a/cspot/protobuf/spirc.proto +++ b/cspot/protobuf/spirc.proto @@ -43,6 +43,8 @@ message State { optional string context_description = 0x8; optional bool shuffle = 0xd; optional bool repeat = 0xe; + optional string last_command_ident = 0x14; + optional uint32 last_command_msgid = 0x15; optional uint32 playing_track_index = 0x1a; repeated TrackRef track = 0x1b; } diff --git a/cspot/src/CDNAudioFile.cpp b/cspot/src/CDNAudioFile.cpp index f58ea07d..8439796a 100644 --- a/cspot/src/CDNAudioFile.cpp +++ b/cspot/src/CDNAudioFile.cpp @@ -39,13 +39,21 @@ void CDNAudioFile::seek(size_t newPos) { this->position = newPos; } +#ifndef CONFIG_BELL_NOCODEC +/** + * @brief Opens connection to the provided cdn url, and fetches track metadata. + */ void CDNAudioFile::openStream() { CSPOT_LOG(info, "Opening HTTP stream to %s", this->cdnUrl.c_str()); // Open connection, read first 128 bytes this->httpConnection = bell::HTTPClient::get( this->cdnUrl, - {bell::HTTPClient::RangeHeader::range(0, OPUS_HEADER_SIZE - 1)}); + {bell::HTTPClient::RangeHeader::range(0, OPUS_HEADER_SIZE - 1)}, 20); + if (!httpConnection->stream().isOpen()) { + this->openStream(); + return; + } this->httpConnection->stream().read((char*)header.data(), OPUS_HEADER_SIZE); this->totalFileSize = @@ -147,12 +155,139 @@ size_t CDNAudioFile::readBytes(uint8_t* dst, size_t bytes) { return bytes; } +#else +/** + * @brief Opens a connection to the CDN URL and fills the first buffer with track header data. + * + * @param header_size Reference to a size_t variable where the size of the header is stored. + * @return Pointer to the beginning of the HTTP buffer where the track header data is stored. + */ +uint8_t* CDNAudioFile::openStream(ssize_t& header_size) { + + // Open connection, fill first buffer + this->httpConnection = bell::HTTPClient::get( + this->cdnUrl, + {bell::HTTPClient::RangeHeader::range(0, HTTP_BUFFER_SIZE - 1)}, 20); + if (!httpConnection->stream().isOpen()) { + return this->openStream(header_size); + } + this->lastRequestPosition = 0; + this->lastRequestCapacity = this->httpConnection->contentLength(); + this->totalFileSize = this->httpConnection->totalLength(); + + this->httpConnection->stream().read((char*)this->httpBuffer.data(), + lastRequestCapacity); + this->decrypt(this->httpBuffer.data(), lastRequestCapacity, + this->lastRequestPosition); + this->position = getHeader(); + header_size = this->position; + return &httpBuffer[0]; +} + +/** + * @brief Finds the position of the first audio frame in the HTTP response. + * + * The OGG Vorbis file starts with three headers. They contain valuable information + * for decoding the audio. + * + * @return The position of the first audio frame in the HTTP response. + */ +long CDNAudioFile::getHeader() { + uint32_t offset = SPOTIFY_OPUS_HEADER; + + for (int i = 0; i < 3; ++i) { + offset += 26; + if (offset >= HTTP_BUFFER_SIZE) { + return HTTP_BUFFER_SIZE; + } + uint8_t segmentCount = httpBuffer[offset]; + uint32_t segmentEnd = segmentCount + offset + 1; + ++offset; + + for (uint32_t j = offset; j < segmentEnd; ++j) { + if (offset >= HTTP_BUFFER_SIZE) { + return HTTP_BUFFER_SIZE; + } + offset += httpBuffer[j]; + } + + if (offset >= HTTP_BUFFER_SIZE) { + return HTTP_BUFFER_SIZE; + } + offset += segmentCount; + } + + return offset; +} + +long CDNAudioFile::readBytes(uint8_t* dst, size_t bytes) { + if (position + bytes >= this->totalFileSize) { + if (position >= this->totalFileSize - 1) { + return 0; + } else { + CSPOT_LOG(info, "Truncating read to %d bytes", + this->totalFileSize - position); + bytes = this->totalFileSize - position; + } + } + + // Position in bounds :) + if (position >= this->lastRequestPosition && + position < this->lastRequestPosition + this->lastRequestCapacity) { + size_t toRead = bytes; + + if ((toRead + position) > this->lastRequestPosition + lastRequestCapacity) { + toRead = this->lastRequestPosition + lastRequestCapacity - position; + } + + memcpy(dst, this->httpBuffer.data() + position - lastRequestPosition, + toRead); + position += toRead; + + return toRead; + } else { + size_t requestPosition = (position) - ((position) % 16); + if (this->enableRequestMargin && requestPosition > SEEK_MARGIN_SIZE) { + requestPosition = + (position - SEEK_MARGIN_SIZE) - ((position - SEEK_MARGIN_SIZE) % 16); + this->enableRequestMargin = false; + } + // Ensure the request range is within file bounds + size_t endPosition = requestPosition + HTTP_BUFFER_SIZE - 1; + if (endPosition > this->totalFileSize) { + endPosition = this->totalFileSize - 1; // Cap the range to the file size + } + + // Only request if the range is valid + if (!this->httpConnection->get( + cdnUrl, {bell::HTTPClient::RangeHeader::range(requestPosition, + endPosition)})) { + return -1; // Handle error if range is invalid or request fails + } + this->lastRequestPosition = requestPosition; + this->lastRequestCapacity = this->httpConnection->contentLength(); + + this->httpConnection->stream().read((char*)this->httpBuffer.data(), + lastRequestCapacity); + this->decrypt(this->httpBuffer.data(), lastRequestCapacity, + + this->lastRequestPosition); + + return readBytes(dst, bytes); + } + + return bytes; +} +#endif size_t CDNAudioFile::getSize() { return this->totalFileSize; } void CDNAudioFile::decrypt(uint8_t* dst, size_t nbytes, size_t pos) { + if (audioKey.size() != 16 && audioKey.size() != 24 && audioKey.size() != 32) { + throw std::runtime_error("Invalid AES key length"); + } auto calculatedIV = bigNumAdd(audioAESIV, pos / 16); this->crypto->aesCTRXcrypt(this->audioKey, calculatedIV, dst, nbytes); diff --git a/cspot/src/DeviceStateHandler.cpp b/cspot/src/DeviceStateHandler.cpp new file mode 100644 index 00000000..b28845e0 --- /dev/null +++ b/cspot/src/DeviceStateHandler.cpp @@ -0,0 +1,1288 @@ +#include "DeviceStateHandler.h" + +#include // for strdup, memcpy, strcpy, strlen +#include // for uint8_t +#include // for unreference, NULL, realloc, rand +#include +#include // for shared_ptr +#include // for remove_extent_t +#include // for swap + +#include "BellLogger.h" // for AbstractLogger +#include "BellUtils.h" // for BELL_SLEEP_MS +#include "CSpotContext.h" // for Context::ConfigState, Context (ptr o... +#include "ConstantParameters.h" // for protocolVersion, swVersion +#include "Logger.h" // for CSPOT_LOG +#include "NanoPBHelper.h" // for pbEncode, pbPutString +#include "Packet.h" // for cspot +#include "TrackReference.h" // for cspot +#include "WrappedSemaphore.h" // for WrappedSemaphore +#include "nlohmann/json.hpp" // for basic_json<>::object_t, basic_json +#include "nlohmann/json_fwd.hpp" // for json +#include "pb.h" // for pb_bytes_array_t, PB_BYTES_ARRAY_T_A... +#include "pb_decode.h" // for pb_release + +using namespace cspot; + +#if defined(_WIN32) || defined(_WIN64) +char* strndup(const char* str, size_t n) { + if (!str) + return nullptr; // Handle null input gracefully + size_t len = std::strlen(str); + if (len > n) + len = n; // Limit to n characters + char* copy = (char*)std::malloc(len + 1); // Allocate memory + if (!copy) + return nullptr; // Return null if allocation fails + std::memcpy(copy, str, len); // Copy the characters + copy[len] = '\0'; // Null-terminate the string + return copy; +} +#endif +static DeviceStateHandler* handler; + +void DeviceStateHandler::reloadTrackList(void* data) { + if (data == NULL) { + if (handler->reloadPreloadedTracks) { + handler->needsToBeSkipped = true; + while (!handler->trackQueue->playableSemaphore->twait(1)) {}; + handler->trackPlayer->start(); + handler->trackPlayer->resetState(); + handler->reloadPreloadedTracks = false; + handler->sendCommand(CommandType::PLAYBACK_START); + handler->device.player_state.track = handler->currentTracks[0]; + } + if (!handler->offset) { + if (handler->trackQueue->preloadedTracks.size()) + handler->trackQueue->preloadedTracks.clear(); + handler->trackQueue->preloadedTracks.push_back( + std::make_shared( + handler->currentTracks[handler->offset], handler->ctx, + handler->trackQueue->playableSemaphore, + handler->offsetFromStartInMillis)); + handler->device.player_state.track = + handler->currentTracks[handler->offset]; + handler->offsetFromStartInMillis = 0; + handler->offset++; + } + if (!handler->trackQueue->preloadedTracks.size()) { + handler->trackQueue->preloadedTracks.push_back( + std::make_shared( + handler->currentTracks[handler->offset - 1], handler->ctx, + handler->trackQueue->playableSemaphore, + handler->offsetFromStartInMillis)); + handler->offsetFromStartInMillis = 0; + } + if (handler->currentTracks.size() > + handler->trackQueue->preloadedTracks.size() + handler->offset) { + while (handler->currentTracks.size() > + handler->trackQueue->preloadedTracks.size() + + handler->offset && + handler->trackQueue->preloadedTracks.size() < 3) { + handler->trackQueue->preloadedTracks.push_back( + std::make_shared( + handler->currentTracks + [handler->offset + + handler->trackQueue->preloadedTracks.size() - 1], + handler->ctx, handler->trackQueue->playableSemaphore)); + } + } + if (handler->playerStateChanged) { + handler->putPlayerState( + PutStateReason::PutStateReason_PLAYER_STATE_CHANGED); + handler->playerStateChanged = false; + } + } + if (strcmp(handler->currentTracks[handler->offset - 1].uri, + "spotify:delimiter") == 0 && + handler->device.player_state.is_playing && + handler->currentTracks.size() <= handler->offset) { + handler->ctx->playbackMetrics->end_reason = cspot::PlaybackMetrics::REMOTE; + handler->ctx->playbackMetrics->end_source = "unknown"; + handler->trackPlayer->stop(); + handler->device.player_state.has_is_playing = true; + handler->device.player_state.is_playing = false; + handler->device.player_state.track = ProvidedTrack_init_zero; + handler->device.player_state.has_track = false; + if (handler->device.player_state.has_restrictions) + pb_release(Restrictions_fields, + &handler->device.player_state.restrictions); + handler->device.player_state.restrictions = Restrictions_init_zero; + handler->device.player_state.has_restrictions = false; + handler->putPlayerState(); + handler->sendCommand(CommandType::DISC); +#ifndef CONFIG_CSPOT_STAY_CONNECTED_ON_TRANSFER + handler->disconnect(); +#endif + return; + } + handler->resolvingContext.store(false); + //CSPOT_LOG(info,"heap_memory_check-safe = %i",heap_caps_check_integrity_all(true)); +} +DeviceStateHandler::DeviceStateHandler(std::shared_ptr ctx, + std::function onClose) { + handler = this; + this->ctx = ctx; + this->onClose = onClose; + this->trackQueue = std::make_shared(ctx); + this->playerContext = std::make_shared( + ctx, &this->device.player_state, ¤tTracks, &offset); + + auto onTrackEnd = [this](bool loaded) { + if (!loaded) {} + CSPOT_LOG(debug, "Ended track"); + if (needsToBeSkipped) { + if (this->device.player_state.options.repeating_track) + this->trackQueue->preloadedTracks[0]->requestedPosition = 0; + else if (this->trackQueue->preloadedTracks.size()) + skip(CommandType::SKIP_NEXT, true); + } + this->device.player_state.timestamp = + this->ctx->timeProvider->getSyncedTimestamp(); + needsToBeSkipped = true; + if (!this->trackQueue->preloadedTracks.size()) + sendCommand(CommandType::DEPLETED); + if ((uint32_t)currentTracks.size() / 2 <= offset && + !this->resolvingContext) { + this->resolvingContext.store(true); + playerContext->resolveTracklist(metadata_map, reloadTrackList); + } + }; + + auto onTrackChanged = [this](std::shared_ptr track, + bool new_track = false) { + if (new_track) { + this->device.player_state.timestamp = + this->trackQueue->preloadedTracks[0] + ->trackMetrics->currentInterval->start; + + this->device.player_state.duration = track->trackInfo.duration; + // this->ctx->timeProvider->getSyncedTimestamp(); + // putPlayerState(PutStateReason::PutStateReason_PICKER_OPENED); + sendCommand(CommandType::PLAYBACK, trackQueue->preloadedTracks[0]); + } else + putPlayerState(); + }; + + this->trackPlayer = std::make_shared( + ctx, trackQueue, onTrackEnd, onTrackChanged, + &device.player_state.options.repeating_track); + CSPOT_LOG(info, "Started player"); + + auto connectStateSubscription = [this](MercurySession::Response res) { + if (res.fail || !res.parts.size()) + return; + if (strstr(res.mercuryHeader.uri, "v1/devices/")) { + putDeviceState(PutStateReason::PutStateReason_SPIRC_NOTIFY); + } else if (strstr(res.mercuryHeader.uri, "player/command")) { + if (res.parts[0].size()) + parseCommand(res.parts[0]); + } else if (strstr(res.mercuryHeader.uri, "volume")) { + if (res.parts[0].size()) { + SetVolumeCommand newVolume; + pbDecode(newVolume, SetVolumeCommand_fields, res.parts[0]); + device.device_info.volume = newVolume.volume; + device.device_info.has_volume = true; + sendCommand(CommandType::VOLUME, newVolume.volume); + pb_release(SetVolumeCommand_fields, &newVolume); + } + } else if (strstr(res.mercuryHeader.uri, "cluster")) { + if (0) { // will send cluster info if new device logged in, but connect_state/cluster is called way too often(for example during each song) too send each time a putPlayerStateRequest + //if(is_active){ + putPlayerState(); + } + } else + CSPOT_LOG(debug, "Unknown connect_state, uri : %s", + res.mercuryHeader.uri); + }; + + this->ctx->session->addSubscriptionListener("hm://connect-state/", + connectStateSubscription); + CSPOT_LOG(info, "Added connect-state subscription"); + + // the device connection status gets reported trough "hm://social-connect",if active + auto socialConnectSubscription = [this](MercurySession::Response res) { + if (res.fail || !res.parts.size()) + return; + if (res.parts[0].size()) { + auto jsonResult = nlohmann::json::parse(res.parts[0]); + if (jsonResult.find("deviceBroadcastStatus") != jsonResult.end()) { + if (jsonResult.find("deviceBroadcastStatus")->find("device_id") != + jsonResult.find("deviceBroadcastStatus")->end()) { + if (jsonResult.find("deviceBroadcastStatus") + ->at("device_id") + .get() != this->ctx->config.deviceId) + goto changePlayerState; + } + } else if (jsonResult.find("reason") != jsonResult.end() && + jsonResult.at("reason") == "SESSION_DELETED") + goto changePlayerState; + return; + changePlayerState: + if (this->is_active) { + this->ctx->playbackMetrics->end_reason = PlaybackMetrics::REMOTE; + this->ctx->playbackMetrics->end_source = "unknown"; + this->trackPlayer->stop(); + this->is_active = false; + if (device.player_state.has_restrictions) + pb_release(Restrictions_fields, &device.player_state.restrictions); + device.player_state.restrictions = Restrictions_init_zero; + device.player_state.has_restrictions = false; + this->putDeviceState(PutStateReason::PutStateReason_BECAME_INACTIVE); + CSPOT_LOG(debug, "Device changed"); + sendCommand(CommandType::DISC); +#ifndef CONFIG_CSPOT_STAY_CONNECTED_ON_TRANSFER + this->disconnect(); +#endif + } + } + }; + + this->ctx->session->addSubscriptionListener("social-connect", + socialConnectSubscription); + CSPOT_LOG(info, "Added social-connect supscription"); + + ctx->session->setConnectedHandler([this]() { + CSPOT_LOG(info, "Registered new device"); + this->putDeviceState( + PutStateReason_SPIRC_HELLO); // : PutStateReason::PutStateReason_NEW_DEVICE); + // Assign country code + this->ctx->config.countryCode = this->ctx->session->getCountryCode(); + }); + + device = {}; + + // Prepare default device state + device.has_device_info = true; + + // Prepare device info + device.device_info.can_play = true; + device.device_info.has_can_play = true; + + device.device_info.has_volume = true; + device.device_info.volume = ctx->config.volume; + + device.device_info.name = strdup(ctx->config.deviceName.c_str()); + + device.device_info.has_capabilities = true; + device.device_info.capabilities = Capabilities{ + true, + 1, //can_be_player + true, + 1, //restrict_to_local + true, + 1, //gaia_eq_connect_id + true, + 0, //supports_logout + true, + 1, //is_observable + true, + 64, //volume_steps + 0, + NULL, //{"audio/track", "audio/episode", "audio/episode+track"}, //supported_types + true, + 1, //command_acks + false, + 0, //supports_rename + false, + 0, //hidden + false, + 0, //disable_volume + false, + 0, //connect_disabled + true, + 1, //supports_playlist_v2 + true, + 1, //is_controllable + true, + 1, //supports_external_episodes + true, + 0, //supports_set_backend_metadata + true, + 1, //supports_transfer_command + false, + 0, //supports_command_request + false, + 0, //is_voice_enabled + true, + 0, //needs_full_player_state //overuses MercuryManager, but keeps connection for outside wlan alive + false, + 0, //supports_gzip_pushes + false, + 0, //supports_lossless_audio + true, + 1, //supports_set_options_command + true, {false, 0, false, 0, true, 1}}; + device.device_info.capabilities.supported_types = + (char**)calloc(5, sizeof(char*)); + device.device_info.capabilities.supported_types[0] = strdup("audio/track"); + device.device_info.capabilities.supported_types[1] = strdup("audio/episode"); + device.device_info.capabilities.supported_types[2] = + strdup("audio/episode+track"); + device.device_info.capabilities.supported_types[3] = + strdup("audio/interruption"); + device.device_info.capabilities.supported_types[4] = strdup("audio/local"); + device.device_info.capabilities.supported_types_count = 5; + device.device_info.device_software_version = strdup(swVersion); + device.device_info.has_device_type = true; + device.device_info.device_type = DeviceType::DeviceType_SPEAKER; + device.device_info.spirc_version = strdup(protocolVersion); + device.device_info.device_id = strdup(ctx->config.deviceId.c_str()); + //device.device_info.client_id + device.device_info.brand = strdup(brandName); + device.device_info.model = strdup(informationString); + //device.device_info.metadata_map = {{"debug_level","1"},{"tier1_port","0"},{"device_address_mask",local_ip}}; + //device.device_info.public_ip = ; // gets added trough server + //device.device_info.license = ; +} + +DeviceStateHandler::~DeviceStateHandler() { + TrackReference::clearProvidedTracklist(¤tTracks); + device.player_state.track = ProvidedTrack_init_zero; + pb_release(Device_fields, &device); +} + +void DeviceStateHandler::putDeviceState(PutStateReason put_state_reason) { + //std::scoped_lock lock(playerStateMutex); + std::string uri = + "hm://connect-state/v1/devices/" + this->ctx->config.deviceId + "/"; + + std::vector send_tracks = {}; + PutStateRequest tempPutReq = PutStateRequest_init_zero; + tempPutReq.has_device = true; + tempPutReq.has_member_type = true; + tempPutReq.member_type = MemberType::MemberType_CONNECT_STATE; + tempPutReq.has_is_active = true; + tempPutReq.is_active = is_active; + tempPutReq.has_put_state_reason = true; + tempPutReq.put_state_reason = put_state_reason; + tempPutReq.has_message_id = true; + tempPutReq.message_id = last_message_id; + tempPutReq.has_has_been_playing_for_ms = true; + tempPutReq.has_been_playing_for_ms = (uint64_t)-1; + tempPutReq.has_client_side_timestamp = true; + tempPutReq.client_side_timestamp = + this->ctx->timeProvider->getSyncedTimestamp(); + tempPutReq.has_only_write_player_state = true; + tempPutReq.only_write_player_state = false; + + if (is_active) { + tempPutReq.has_started_playing_at = true; + tempPutReq.started_playing_at = this->started_playing_at; + tempPutReq.has_been_playing_for_ms = + this->ctx->timeProvider->getSyncedTimestamp() - + this->started_playing_at; + device.has_player_state = true; + device.player_state.has_position_as_of_timestamp = true; + device.player_state.position_as_of_timestamp = + this->ctx->timeProvider->getSyncedTimestamp() - + device.player_state.timestamp; + } else + device.has_player_state = false; + device.player_state.next_tracks.funcs.encode = + &cspot::TrackReference::pbEncodeProvidedTracks; + device.player_state.next_tracks.arg = &queuePacket; + tempPutReq.device = this->device; + + auto putStateRequest = pbEncode(PutStateRequest_fields, &tempPutReq); + tempPutReq.device = Device_init_zero; + pb_release(PutStateRequest_fields, &tempPutReq); + auto parts = MercurySession::DataParts({putStateRequest}); + auto responseLambda = [this](MercurySession::Response res) { + if (res.fail || !res.parts.size()) + return; + }; + this->ctx->session->execute(MercurySession::RequestType::PUT, uri, + responseLambda, parts); +} + +void DeviceStateHandler::putPlayerState(PutStateReason put_state_reason) { + //std::scoped_lock lock(playerStateMutex); + std::string uri = + "hm://connect-state/v1/devices/" + this->ctx->config.deviceId + "/"; + PutStateRequest tempPutReq = {}; + pb_release(PutStateRequest_fields, &tempPutReq); + tempPutReq = PutStateRequest_init_zero; + tempPutReq.has_device = true; + tempPutReq.has_member_type = false; + tempPutReq.member_type = MemberType::MemberType_CONNECT_STATE; + tempPutReq.has_is_active = true; + tempPutReq.is_active = true; + tempPutReq.has_put_state_reason = true; + tempPutReq.put_state_reason = put_state_reason; + tempPutReq.last_command_message_id = last_message_id; + tempPutReq.has_started_playing_at = true; + tempPutReq.started_playing_at = + this->trackQueue->preloadedTracks[0]->trackMetrics->trackHeaderTime; + tempPutReq.has_has_been_playing_for_ms = true; + tempPutReq.has_been_playing_for_ms = + this->ctx->timeProvider->getSyncedTimestamp() - + this->trackQueue->preloadedTracks[0]->trackMetrics->trackHeaderTime; + tempPutReq.has_client_side_timestamp = true; + tempPutReq.client_side_timestamp = + this->ctx->timeProvider->getSyncedTimestamp(); + tempPutReq.has_only_write_player_state = true; + tempPutReq.only_write_player_state = true; + device.player_state.has_position_as_of_timestamp = true; + device.player_state.timestamp = + trackQueue->preloadedTracks[0]->trackMetrics->currentInterval->start; + device.player_state.position_as_of_timestamp = + (int64_t)trackQueue->preloadedTracks[0]->trackMetrics->getPosition(); + device.has_player_state = true; + device.player_state.has_position_as_of_timestamp = true; + device.player_state.position_as_of_timestamp = + trackQueue->preloadedTracks[0]->trackMetrics->getPosition(); + queuePacket = {&offset, ¤tTracks}; + device.player_state.next_tracks.funcs.encode = + &cspot::TrackReference::pbEncodeProvidedTracks; + device.player_state.next_tracks.arg = &queuePacket; + if (device.player_state.track.provider && + strcmp(device.player_state.track.provider, "autoplay") == 0) { + if (device.player_state.has_restrictions) + pb_release(Restrictions_fields, &device.player_state.restrictions); + pb_release(ContextIndex_fields, &device.player_state.index); + device.player_state.index = ContextIndex_init_zero; + device.player_state.has_index = false; + device.player_state.restrictions = Restrictions_init_zero; + if (!device.player_state.is_paused) { + device.player_state.restrictions.disallow_resuming_reasons = + (char**)calloc(1, sizeof(char*)); + device.player_state.restrictions.disallow_resuming_reasons_count = 1; + device.player_state.restrictions.disallow_resuming_reasons[0] = + strdup("not_paused"); + } else { + device.player_state.restrictions.disallow_pausing_reasons = + (char**)calloc(1, sizeof(char*)); + device.player_state.restrictions.disallow_pausing_reasons_count = 1; + device.player_state.restrictions.disallow_pausing_reasons[0] = + strdup("not_playing"); + } + // Update player state with current track information + device.player_state.restrictions.disallow_toggling_repeat_context_reasons = + (char**)calloc(3, sizeof(char*)); + device.player_state.restrictions + .disallow_toggling_repeat_context_reasons_count = 3; + device.player_state.restrictions + .disallow_toggling_repeat_context_reasons[0] = strdup("autoplay"); + device.player_state.restrictions + .disallow_toggling_repeat_context_reasons[1] = + strdup("endless_context"); + device.player_state.restrictions + .disallow_toggling_repeat_context_reasons[2] = strdup("radio"); + + device.player_state.restrictions.disallow_toggling_repeat_track_reasons = + (char**)calloc(1, sizeof(char*)); + device.player_state.restrictions + .disallow_toggling_repeat_track_reasons_count = 1; + device.player_state.restrictions.disallow_toggling_repeat_track_reasons[0] = + strdup("autoplay"); + + device.player_state.restrictions.disallow_toggling_shuffle_reasons = + (char**)calloc(3, sizeof(char*)); + device.player_state.restrictions.disallow_toggling_shuffle_reasons_count = + 3; + device.player_state.restrictions.disallow_toggling_shuffle_reasons[0] = + strdup("autoplay"); + device.player_state.restrictions.disallow_toggling_shuffle_reasons[1] = + strdup("endless_context"); + device.player_state.restrictions.disallow_toggling_shuffle_reasons[2] = + strdup("radio"); + + device.player_state.restrictions.disallow_loading_context_reasons = + (char**)calloc(1, sizeof(char*)); + device.player_state.restrictions.disallow_loading_context_reasons_count = 1; + device.player_state.restrictions.disallow_loading_context_reasons[0] = + strdup("not_supported_by_content_type"); + + device.player_state.has_index = false; + device.player_state.has_restrictions = true; + if (device.player_state.play_origin.feature_classes != NULL) { + free(device.player_state.play_origin.feature_classes); + device.player_state.play_origin.feature_classes = NULL; + } + } else { + device.player_state.index = + ContextIndex{true, device.player_state.track.page, true, + device.player_state.track.original_index}; + if (device.player_state.has_restrictions) + pb_release(Restrictions_fields, &device.player_state.restrictions); + device.player_state.restrictions = Restrictions_init_zero; + if (!device.player_state.is_paused) { + device.player_state.restrictions.disallow_resuming_reasons = + (char**)calloc(1, sizeof(char*)); + device.player_state.restrictions.disallow_resuming_reasons_count = 1; + device.player_state.restrictions.disallow_resuming_reasons[0] = + strdup("not_paused"); + } else { + device.player_state.restrictions.disallow_pausing_reasons = + (char**)calloc(1, sizeof(char*)); + device.player_state.restrictions.disallow_pausing_reasons_count = 1; + device.player_state.restrictions.disallow_pausing_reasons[0] = + strdup("not_playing"); + } + device.player_state.restrictions.disallow_loading_context_reasons = + (char**)calloc(1, sizeof(char*)); + device.player_state.restrictions.disallow_loading_context_reasons_count = 1; + device.player_state.restrictions.disallow_loading_context_reasons[0] = + strdup("not_supported_by_content_type"); + + device.player_state.has_restrictions = true; + } + tempPutReq.device = this->device; + auto putStateRequest = pbEncode(PutStateRequest_fields, &tempPutReq); + tempPutReq.device = Device_init_zero; + pb_release(PutStateRequest_fields, &tempPutReq); + auto parts = MercurySession::DataParts({putStateRequest}); + + auto responseLambda = [this](MercurySession::Response res) { + if (res.fail || !res.parts.size()) + return; + }; + this->ctx->session->execute(MercurySession::RequestType::PUT, uri, + responseLambda, parts); +} + +void DeviceStateHandler::disconnect() { + if (this->is_active) { + this->ctx->playbackMetrics->end_reason = PlaybackMetrics::REMOTE; + this->ctx->playbackMetrics->end_source = "unknown"; + this->trackPlayer->stop(); + this->is_active = false; + if (device.player_state.has_restrictions) + pb_release(Restrictions_fields, &device.player_state.restrictions); + device.player_state.restrictions = Restrictions_init_zero; + device.player_state.has_restrictions = false; + this->putDeviceState(PutStateReason::PutStateReason_BECAME_INACTIVE); + CSPOT_LOG(debug, "Device changed"); + sendCommand(CommandType::DISC); + } + this->trackQueue->preloadedTracks.clear(); + this->trackQueue->stopTask(); + this->ctx->session->disconnect(); + this->onClose(); +} + +void DeviceStateHandler::skip(CommandType dir, bool notify) { + if (dir == CommandType::SKIP_NEXT) { + this->device.player_state.track = currentTracks[offset]; + if (this->device.player_state.track.full_metadata_count > + this->device.player_state.track.metadata_count) + this->device.player_state.track.metadata_count = + this->device.player_state.track.full_metadata_count; + if (trackQueue->preloadedTracks.size()) { + trackQueue->preloadedTracks.pop_front(); + if (currentTracks.size() > + (trackQueue->preloadedTracks.size() + offset)) { + while (currentTracks.size() > + trackQueue->preloadedTracks.size() + offset && + trackQueue->preloadedTracks.size() < 3) { + trackQueue->preloadedTracks.push_back( + std::make_shared( + currentTracks[offset + trackQueue->preloadedTracks.size()], + this->ctx, this->trackQueue->playableSemaphore)); + } + } + offset++; + } + } else if (trackQueue->preloadedTracks[0]->trackMetrics->getPosition() >= + 3000 && + offset > 1) { + trackQueue->preloadedTracks.pop_back(); + offset--; + trackQueue->preloadedTracks.push_front(std::make_shared( + currentTracks[offset - 1], this->ctx, + this->trackQueue->playableSemaphore)); + } else { + if (trackQueue->preloadedTracks.size()) + trackQueue->preloadedTracks[0]->requestedPosition = 0; + } + if (trackQueue->preloadedTracks.size() && + currentTracks.size() < offset + trackQueue->preloadedTracks.size()) { + playerContext->resolveTracklist(metadata_map, reloadTrackList); + } + if (!trackQueue->preloadedTracks.size()) + this->trackPlayer->stop(); + else if (!notify) + trackPlayer->resetState(); +} + +void DeviceStateHandler::parseCommand(std::vector& data) { + if (data.size() <= 2) + return; + nlohmann::json jsonResult; + try { + jsonResult = nlohmann::json::parse(data); + } catch (const nlohmann::json::parse_error&) { + CSPOT_LOG(error, "Failed to parse command"); + return; // Parsing failed + } + last_message_id = jsonResult.value("message_id", last_message_id); + + auto command = jsonResult.find("command"); + if (command != jsonResult.end()) { + if (command->find("endpoint") == command->end()) + return; + CSPOT_LOG(debug, "Parsing new command, endpoint : %s", + command->at("endpoint").get().c_str()); + + auto options = command->find("options"); + if (command->at("endpoint") == "transfer") { + if (is_active) + return; + if (options != command->end()) { + if (options->find("restore_paused") != + options->end()) { //"restore"==play + if (!is_active && options->at("restore_paused") == "restore") { + started_playing_at = this->ctx->timeProvider->getSyncedTimestamp(); + is_active = true; + } + } + } + if (this->playerContext->next_page_url != NULL) + unreference(&(this->playerContext->next_page_url)); + this->playerContext->radio_offset = 0; + this->device.player_state.has_is_playing = true; + this->device.player_state.is_playing = true; + this->device.player_state.has_timestamp = true; + this->device.player_state.timestamp = + this->ctx->timeProvider->getSyncedTimestamp(); + if (!is_active) { + started_playing_at = this->ctx->timeProvider->getSyncedTimestamp(); + is_active = true; + } + auto logging_params = command->find("logging_params"); + if (logging_params != command->end()) { + metadata_map.clear(); + if (logging_params->find("page_instance_ids") != + logging_params->end()) { + metadata_map.push_back(std::make_pair( + "page_instance_id", + logging_params->at("page_instance_ids")[0].get())); + } + + if (logging_params->find("interaction_ids") != logging_params->end()) { + metadata_map.push_back(std::make_pair( + "interaction_id", + logging_params->at("interaction_ids")[0].get())); + } + } + auto responseHandler = [this](MercurySession::Response res) { + if (res.fail || !res.parts.size()) + return; + cspot::TrackReference::clearProvidedTracklist(¤tTracks); + currentTracks = {}; + Cluster cluster = {}; + for (int i = this->device.player_state.context_metadata_count - 1; + i >= 0; i--) { + unreference(&(this->device.player_state.context_metadata[i].key)); + unreference(&(this->device.player_state.context_metadata[i].value)); + } + free(this->device.player_state.context_metadata); + this->device.player_state.context_metadata = NULL; + this->device.player_state.context_metadata_count = 0; + device.player_state.track = ProvidedTrack_init_zero; + device.player_state.next_tracks.arg = NULL; + if (device.player_state.has_restrictions) + pb_release(Restrictions_fields, &device.player_state.restrictions); + device.player_state.restrictions = Restrictions_init_zero; + device.player_state.has_restrictions = false; + pb_release(PlayerState_fields, &this->device.player_state); + this->device.player_state = PlayerState_init_zero; + pb_release(Cluster_fields, &cluster); + cluster.player_state.next_tracks.funcs.decode = + &cspot::TrackReference::pbDecodeProvidedTracks; + cluster.player_state.next_tracks.arg = &this->currentTracks; + + pbDecode(cluster, Cluster_fields, res.parts[0]); + this->device.player_state = cluster.player_state; + cluster.player_state = PlayerState_init_zero; + pb_release(Cluster_fields, &cluster); + offsetFromStartInMillis = device.player_state.position_as_of_timestamp; + + std::vector random_bytes; + static std::uniform_int_distribution d(0, 255); + for (int i = 0; i < 16; i++) { + random_bytes.push_back(d(ctx->rng)); + } + unreference(&(this->device.player_state.session_id)); + this->device.player_state.session_id = + strdup(bytesToHexString(random_bytes).c_str()); + + unreference(&(this->device.player_state.playback_id)); + random_bytes.clear(); + for (int i = 0; i < 16; i++) { + random_bytes.push_back(d(ctx->rng)); + } + this->device.player_state.playback_id = + strdup(base64Encode(random_bytes).c_str()); + + this->currentTracks.insert(this->currentTracks.begin(), + this->device.player_state.track); + offset = 0; + + queuePacket = {&offset, ¤tTracks}; + this->putDeviceState( + PutStateReason::PutStateReason_PLAYER_STATE_CHANGED); + + trackQueue->preloadedTracks.clear(); + reloadPreloadedTracks = true; + playerContext->resolveTracklist(metadata_map, reloadTrackList, true); + }; + this->ctx->session->execute(MercurySession::RequestType::GET, + "hm://connect-state/v1/cluster", + responseHandler); + } else if (this->is_active) { + if (command->at("endpoint") == "play") { +#ifndef CONFIG_BELL_NOCODEC + handler->trackPlayer->stop(); + sendCommand(CommandType::DEPLETED); +#endif + if (this->playerContext->next_page_url != NULL) + unreference(&(this->playerContext->next_page_url)); + this->playerContext->radio_offset = 0; + trackQueue->preloadedTracks.clear(); + uint8_t queued = 0; + ProvidedTrack track = ProvidedTrack_init_zero; + if (!this->device.player_state.is_playing) { + this->device.player_state.is_playing = true; + this->device.player_state.has_track = true; + } + for (int i = 0; i < currentTracks.size(); i++) { + if (i > this->offset || currentTracks[i].provider == NULL || + strcmp(currentTracks[i].provider, "queue") != 0) { + cspot::TrackReference::pbReleaseProvidedTrack(¤tTracks[i]); + currentTracks.erase(currentTracks.begin() + i); + i--; + } + } + + auto logging_params = command->find("logging_params"); + if (logging_params != command->end()) { + metadata_map.clear(); + if (logging_params->find("page_instance_ids") != + logging_params->end()) { + metadata_map.push_back(std::make_pair( + "page_instance_ids", + logging_params->at("page_instance_ids")[0].get())); + } + if (logging_params->find("interaction_ids") != + logging_params->end()) { + metadata_map.push_back(std::make_pair( + "interaction_id", + logging_params->at("interaction_ids")[0].get())); + } + } + + if (command->find("play_origin") != command->end()) { + pb_release(PlayOrigin_fields, &device.player_state.play_origin); + device.player_state.play_origin = PlayOrigin_init_zero; + device.player_state.play_origin.feature_identifier = + PlayerContext::createStringReferenceIfFound( + command->at("play_origin"), "feature_identifier"); + device.player_state.play_origin.feature_version = + PlayerContext::createStringReferenceIfFound( + command->at("play_origin"), "feature_version"); + device.player_state.play_origin.referrer_identifier = + PlayerContext::createStringReferenceIfFound( + command->at("play_origin"), "referrer_identifier"); + } + + auto options = command->find("options"); + int64_t playlist_offset = 0; + if (options != command->end()) { + if (options->find("player_options_override") != options->end() && + options->at("player_options_override") + .find("shuffling_context") != + options->at("player_options_override").end()) + device.player_state.options.shuffling_context = + options->at("player_options_override").at("shuffling_context"); + else + device.player_state.options.shuffling_context = false; + if (options->find("skip_to") != options->end()) { + if (options->at("skip_to").size()) { + if (options->at("skip_to").find("track_index") != + options->at("skip_to").end()) { + playlist_offset = options->at("skip_to").at("track_index"); + track.original_index = playlist_offset; + } + track.uri = PlayerContext::createStringReferenceIfFound( + options->at("skip_to"), "track_uri"); + track.uid = PlayerContext::createStringReferenceIfFound( + options->at("skip_to"), "track_uid"); + } + } + } + + auto metadata = command->at("context").find("metadata"); + if (metadata != command->at("context").end()) { + if (metadata->find("enhanced_context") != metadata->end()) { + this->device.player_state.options.context_enhancement[0].key = + strdup("context_enhancement"); + this->device.player_state.options.context_enhancement[0].value = + strdup("NONE"); + this->device.player_state.options.context_enhancement_count = 1; + } else if (this->device.player_state.options + .context_enhancement_count) { + for (auto& enhamcement : + this->device.player_state.options.context_enhancement) { + this->unreference(&(enhamcement.key)); + this->unreference(&(enhamcement.value)); + } + this->device.player_state.options.context_enhancement_count = 0; + } + + context_metadata_map.clear(); + for (auto element : metadata->items()) { + if (element.value().size() && element.value() != "" && + element.key() != "canContainArtists.uris") { + context_metadata_map.push_back(std::make_pair( + element.key(), element.value().get())); + } + } + for (int i = this->device.player_state.context_metadata_count - 1; + i >= 0; i--) { + unreference(&(this->device.player_state.context_metadata[i].key)); + unreference(&(this->device.player_state.context_metadata[i].value)); + } + free(this->device.player_state.context_metadata); + this->device.player_state.context_metadata = + (PlayerState_ContextMetadataEntry*)calloc( + context_metadata_map.size(), + sizeof(PlayerState_ContextMetadataEntry)); + for (int i = 0; i < context_metadata_map.size(); i++) { + this->device.player_state.context_metadata[i].key = + strdup(context_metadata_map[i].first.c_str()); + this->device.player_state.context_metadata[i].value = + strdup(context_metadata_map[i].second.c_str()); + } + this->device.player_state.context_metadata_count = + context_metadata_map.size(); + } else { + if (this->device.player_state.options.context_enhancement_count) { + for (auto& enhamcement : + this->device.player_state.options.context_enhancement) { + this->unreference(&(enhamcement.key)); + this->unreference(&(enhamcement.value)); + } + this->device.player_state.options.context_enhancement_count = 0; + } + context_metadata_map.clear(); + for (int i = this->device.player_state.context_metadata_count - 1; + i >= 0; i--) { + unreference(&(this->device.player_state.context_metadata[i].key)); + unreference(&(this->device.player_state.context_metadata[i].value)); + } + free(this->device.player_state.context_metadata); + this->device.player_state.context_metadata = NULL; + this->device.player_state.context_metadata_count = 0; + } + + unreference(&(this->device.player_state.context_uri)); + this->device.player_state.context_uri = + PlayerContext::createStringReferenceIfFound(command->at("context"), + "uri"); + unreference(&(this->device.player_state.context_url)); + this->device.player_state.context_url = + PlayerContext::createStringReferenceIfFound(command->at("context"), + "url"); + reloadPreloadedTracks = true; + //this->trackPlayer->start(); + uint8_t metadata_offset = 0; + for (auto metadata_entry : metadata_map) { + track.metadata[metadata_offset].key = + strdup(metadata_entry.first.c_str()); + track.metadata[metadata_offset].value = + strdup(metadata_entry.second.c_str()); + metadata_offset++; + } + + if (command->at("context").find("pages") != + command->at("context").end() && + command->at("context").at("pages")[0]["tracks"].size() > + playlist_offset) { + //populate first tarck + if (track.uri == NULL) { + track.uri = PlayerContext::createStringReferenceIfFound( + command->at("context")["pages"][0]["tracks"][playlist_offset], + "uri"); + track.uid = PlayerContext::createStringReferenceIfFound( + command->at("context")["pages"][0]["tracks"][playlist_offset], + "uid"); + } + if (command->at("context")["pages"][0]["tracks"][playlist_offset] + .find("metadata") != + command->at("context")["pages"][0]["tracks"][playlist_offset] + .end()) { + for (auto metadata_entry : + command->at("context")["pages"][0]["tracks"][playlist_offset] + .at("metadata") + .items()) { + track.metadata[metadata_offset].key = + strdup(metadata_entry.key().c_str()); + track.metadata[metadata_offset].value = + strdup(((std::string)metadata_entry.value()).c_str()); + metadata_offset++; + } + } + } + track.full_metadata_count = metadata_offset; + track.metadata_count = metadata_offset; + if (this->device.player_state.context_url != NULL && + strchr(this->device.player_state.context_url, ':') != NULL) { + track.provider = + strndup(this->device.player_state.context_url, + strchr(this->device.player_state.context_url, ':') - + this->device.player_state.context_url); + } else if (strchr(this->device.player_state.context_uri, ':') != + strrchr(this->device.player_state.context_uri, ':')) { + track.provider = strdup("context"); + } + if (track.uri) { + currentTracks.insert(currentTracks.begin(), track); + device.player_state.track = track; + } else + pb_release(ProvidedTrack_fields, &track); + offset = 0; + this->playerContext->resolveTracklist(metadata_map, reloadTrackList, + true, true); + CSPOT_LOG(info, "Tracklist reloaded"); + } else if (command->at("endpoint") == "pause") { + device.player_state.is_paused = true; + device.player_state.has_is_paused = true; + this->putPlayerState(); + sendCommand(CommandType::PAUSE); + } else if (command->at("endpoint") == "resume") { + device.player_state.is_paused = false; + device.player_state.has_is_paused = true; + this->putPlayerState(); + sendCommand(CommandType::PLAY); + } else if (command->at("endpoint") == "skip_next") { + ctx->playbackMetrics->end_reason = PlaybackMetrics::FORWARD_BTN; +#ifndef CONFIG_BELL_NOCODEC + this->needsToBeSkipped = false; +#endif + if (command->find("track") == command->end()) + skip(CommandType::SKIP_NEXT, false); + else { + offset = 0; + for (auto track : currentTracks) { + if (strcmp(command->find("track") + ->at("uri") + .get() + .c_str(), + track.uri) == 0) + break; + offset++; + } + trackQueue->preloadedTracks.clear(); + + this->device.player_state.track = currentTracks[offset]; + for (auto i = offset; + i < (currentTracks.size() < 3 + offset ? currentTracks.size() + : 3 + offset); + i++) { + trackQueue->preloadedTracks.push_back( + std::make_shared( + currentTracks[i], this->ctx, + this->trackQueue->playableSemaphore)); + } + offset++; + trackPlayer->resetState(); + } + sendCommand(CommandType::SKIP_NEXT); + } else if (command->at("endpoint") == "skip_prev") { + ctx->playbackMetrics->end_reason = PlaybackMetrics::BACKWARD_BTN; + needsToBeSkipped = false; + skip(CommandType::SKIP_PREV, false); + sendCommand(CommandType::SKIP_PREV); + + } else if (command->at("endpoint") == "seek_to") { + +#ifndef CONFIG_BELL_NOCODEC + if (!this->trackQueue->preloadedTracks[0]->loading) + needsToBeSkipped = false; +#endif + if (command->at("relative") == "beginning") { //relative + this->device.player_state.has_position_as_of_timestamp = true; + this->device.player_state.position_as_of_timestamp = + command->at("value").get(); + this->device.player_state.timestamp = + this->ctx->timeProvider->getSyncedTimestamp(); + this->trackPlayer->seekMs( + command->at("value").get(), + this->trackQueue->preloadedTracks[0]->loading); + } else if (command->at("relative") == "current") { + this->device.player_state.has_position_as_of_timestamp = true; + this->device.player_state.position_as_of_timestamp = + command->at("value").get() + + command->at("position").get(); + this->trackPlayer->seekMs( + this->device.player_state.position_as_of_timestamp, + this->trackQueue->preloadedTracks[0]->loading); + this->device.player_state.timestamp = + this->ctx->timeProvider->getSyncedTimestamp(); + } + sendCommand( + CommandType::SEEK, + (int32_t)this->device.player_state.position_as_of_timestamp); + this->putPlayerState(); + } else if (command->at("endpoint") == "add_to_queue") { + uint8_t queuedOffset = 0; + //look up already queued tracks + for (uint8_t i = offset; i < currentTracks.size(); i++) { + if (strcmp(currentTracks[i].provider, "queue") != 0) + break; + queuedOffset++; + } + + ProvidedTrack track = {}; + track.uri = strdup( + command->find("track")->at("uri").get().c_str()); + track.provider = strdup("queue"); + this->currentTracks.insert( + this->currentTracks.begin() + offset + queuedOffset, track); + if (queuedOffset < 2) { + trackQueue->preloadedTracks.pop_back(); + trackQueue->preloadedTracks.insert( + trackQueue->preloadedTracks.begin() + 1 + queuedOffset, + std::make_shared( + currentTracks[offset + queuedOffset], this->ctx, + this->trackQueue->playableSemaphore)); + } +#ifndef CONFIG_BELL_NOCODEC + this->trackPlayer->seekMs( + trackQueue->preloadedTracks[0]->trackMetrics->getPosition(), + this->trackQueue->preloadedTracks[0]->loading); + sendCommand( + CommandType::SEEK, + (int32_t)this->device.player_state.position_as_of_timestamp); +#endif + this->putPlayerState(); + } else if (command->at("endpoint") == "set_queue") { + uint8_t queuedOffset = 0, newQueuedOffset = 0; + //look up already queued tracks + for (uint8_t i = offset; i < currentTracks.size(); i++) { + if (strcmp(currentTracks[i].provider, "queue") != 0) + break; + queuedOffset++; + } + auto tracks = command->find("next_tracks"); + if (!command->at("next_tracks").size()) { + for (uint8_t i = offset; i < currentTracks.size(); i++) { + if (strcmp(currentTracks[i].provider, "queue") != 0) + break; + cspot::TrackReference::pbReleaseProvidedTrack(¤tTracks[i]); + currentTracks.erase(currentTracks.begin() + i); + i--; + } + } + if (command->find("next_tracks") != command->end()) { + for (int i = 0; i < command->at("next_tracks").size(); i++) { + if (strcmp(command->at("next_tracks")[i]["uri"] + .get() + .c_str(), + currentTracks[offset + i].uri) != 0) { + if (newQueuedOffset < queuedOffset) { + queuedOffset--; + goto removeTrack; + } else if (command->at("next_tracks")[i]["provider"] == "queue") { + ProvidedTrack track = {}; + track.uri = strdup(command->at("next_tracks")[i]["uri"] + .get() + .c_str()); + track.provider = strdup("queue"); + this->currentTracks.insert( + this->currentTracks.begin() + offset + i, track); + continue; + } + removeTrack:; + cspot::TrackReference::pbReleaseProvidedTrack( + ¤tTracks[offset + i]); + currentTracks.erase(currentTracks.begin() + offset + i); + if (strcmp(currentTracks[offset + i].provider, "queue") != 0 || + strcmp(command->at("next_tracks")[i]["uri"] + .get() + .c_str(), + currentTracks[offset + i].uri) == 0) + break; + i--; + } else if (command->at("next_tracks")[i]["provider"] == "queue") + newQueuedOffset++; + } + } + if (queuedOffset < 2 || newQueuedOffset < 2) { + trackQueue->preloadedTracks.clear(); + while (trackQueue->preloadedTracks.size() < 3) + trackQueue->preloadedTracks.push_back( + std::make_shared( + currentTracks[offset + trackQueue->preloadedTracks.size() - + 1], + this->ctx, this->trackQueue->playableSemaphore)); + } +#ifndef CONFIG_BELL_NOCODEC + this->trackPlayer->seekMs( + trackQueue->preloadedTracks[0]->trackMetrics->getPosition(), + this->trackQueue->preloadedTracks[0]->loading); + sendCommand( + CommandType::SEEK, + (int32_t)this->device.player_state.position_as_of_timestamp); +#endif + this->putPlayerState(); + } else if (command->at("endpoint") == "update_context") { + unreference(&(this->device.player_state.session_id)); + this->device.player_state.session_id = + PlayerContext::createStringReferenceIfFound(*command, "session_id"); + + auto context = command->find("context"); + if (context != command->end()) { + if (context_metadata_map.size()) + context_metadata_map.clear(); + context_uri = context->find("uri") != context->end() + ? context->at("uri").get() + : " "; + context_url = context->find("url") != context->end() + ? context->at("url").get() + : " "; + auto metadata = context->find("metadata"); + if (metadata != context->end()) { + for (auto element : metadata->items()) { + if (element.value().size() && element.value() != "") { + context_metadata_map.push_back(std::make_pair( + element.key(), element.value().get())); + } + } + } + } + } else if (command->at("endpoint") == "set_shuffling_context") { + if (context_uri.size()) { + unreference(&(this->device.player_state.context_uri)); + this->device.player_state.context_uri = strdup(context_uri.c_str()); + } + if (context_url.size()) { + unreference(&(this->device.player_state.context_url)); + this->device.player_state.context_url = strdup(context_url.c_str()); + } + for (int i = this->device.player_state.context_metadata_count - 1; + i >= 0; i--) { + unreference(&(this->device.player_state.context_metadata[i].key)); + unreference(&(this->device.player_state.context_metadata[i].value)); + } + free(this->device.player_state.context_metadata); + this->device.player_state.context_metadata = + (PlayerState_ContextMetadataEntry*)calloc( + context_metadata_map.size(), + sizeof(PlayerState_ContextMetadataEntry)); + for (int i = 0; i < context_metadata_map.size(); i++) { + this->device.player_state.context_metadata[i].key = + strdup(context_metadata_map[i].first.c_str()); + this->device.player_state.context_metadata[i].value = + strdup(context_metadata_map[i].second.c_str()); + } + this->device.player_state.context_metadata_count = + context_metadata_map.size(); + + this->device.player_state.has_options = true; + this->device.player_state.options.has_shuffling_context = true; + if (command->find("value").value()) + this->device.player_state.options.shuffling_context = true; + else + this->device.player_state.options.shuffling_context = false; + if (strchr(this->device.player_state.context_url, '?') != NULL) { + this->device.player_state.options.context_enhancement[0].key = + strdup("context_enhancement"); + this->device.player_state.options.context_enhancement[0].value = + strdup("NONE"); + this->device.player_state.options.context_enhancement_count = 1; + } else { + if (this->device.player_state.options.context_enhancement_count) { + unreference(&( + this->device.player_state.options.context_enhancement[0].key)); + unreference( + &(this->device.player_state.options.context_enhancement[0] + .value)); + this->device.player_state.options.context_enhancement_count = 0; + } + } + playerStateChanged = true; + this->trackQueue->preloadedTracks.erase( + this->trackQueue->preloadedTracks.begin(), + this->trackQueue->preloadedTracks.end()); + for (int i = offset; i < currentTracks.size(); i++) { + if (strcmp(currentTracks[i].provider, "queue") != 0) { + cspot::TrackReference::pbReleaseProvidedTrack( + ¤tTracks[offset + i]); + currentTracks.erase(currentTracks.begin() + offset + i); + i--; + } + } + playerContext->resolveTracklist(metadata_map, reloadTrackList, true); + sendCommand(CommandType::SET_SHUFFLE, + (int32_t)(this->device.player_state.options + .context_enhancement_count + ? 2 + : this->device.player_state.options + .shuffling_context)); +#ifndef CONFIG_BELL_NOCODEC + this->trackPlayer->seekMs( + trackQueue->preloadedTracks[0]->trackMetrics->getPosition(), + this->trackQueue->preloadedTracks[0]->loading); + sendCommand( + CommandType::SEEK, + (int32_t)this->device.player_state.position_as_of_timestamp); +#endif + } else if (command->at("endpoint") == "set_options") { + + if (this->device.player_state.options.repeating_context != + command->at("repeating_context").get()) { + uint8_t release = 0; + for (int i = offset; i < currentTracks.size(); i++) + if (strcmp(currentTracks[i].uri, "spotify:delimiter") == 0 || + strcmp(currentTracks[i].provider, "autoplay") == 0) { + release = i; + break; + } + if (release) { + for (int i = release; i < currentTracks.size(); i++) + cspot::TrackReference::pbReleaseProvidedTrack(¤tTracks[i]); + currentTracks.erase(currentTracks.begin() + release, + currentTracks.end()); + } + + this->device.player_state.options.has_repeating_context = true; + this->device.player_state.options.repeating_context = + command->at("repeating_context").get(); + this->device.player_state.options.repeating_track = + command->at("repeating_track").get(); + this->device.player_state.options.has_repeating_track = true; + playerStateChanged = true; + this->playerContext->resolveTracklist(metadata_map, reloadTrackList, + true); + } else { + this->device.player_state.options.has_repeating_context = true; + this->device.player_state.options.repeating_context = + command->at("repeating_context").get(); + this->device.player_state.options.repeating_track = + command->at("repeating_track").get(); + this->device.player_state.options.has_repeating_track = true; + this->putPlayerState(); + } + if (this->device.player_state.options.repeating_context) + sendCommand( + CommandType::SET_REPEAT, + (int32_t)(this->device.player_state.options.repeating_context + ? 2 + : this->device.player_state.options + .repeating_track)); + } else + CSPOT_LOG(error, "Unknown command: %s", + &command->at("endpoint").get()[0]); + return; + } + } +} +void DeviceStateHandler::sendCommand(CommandType type, CommandData data) { + Command command; + command.commandType = type; + command.data = data; + stateCallback(command); +} \ No newline at end of file diff --git a/cspot/src/EventManager.cpp b/cspot/src/EventManager.cpp new file mode 100644 index 00000000..042b9c76 --- /dev/null +++ b/cspot/src/EventManager.cpp @@ -0,0 +1,284 @@ +#include "EventManager.h" +#include "CSpotContext.h" // for Context::ConfigState, Context (ptr o... +#include "Logger.h" // for CSPOT_LOG +#include "TrackQueue.h" + +using namespace cspot; + +static std::string reason_text[11] = { + "trackdone", "trackerror", "fwdbtn", "backbtn", "endplay", "playbtn", + "clickrow", "logout", "appload", "remote", ""}; + +TrackMetrics::TrackMetrics(std::shared_ptr ctx, uint64_t pos) { + this->ctx = ctx; + timestamp = ctx->timeProvider->getSyncedTimestamp(); + currentInterval = std::make_shared(timestamp, pos); +} + +void TrackMetrics::endInterval(uint64_t pos) { + // end Interval + currentInterval->length = + this->ctx->timeProvider->getSyncedTimestamp() - currentInterval->start; + currentInterval->end = currentInterval->position + currentInterval->length; + totalAmountPlayed += currentInterval->length; + // add skipped time + if (pos != 0) { + if (pos > currentInterval->position + currentInterval->length) + skipped_forward.add( + pos - (currentInterval->position + currentInterval->length)); + else + skipped_backward.add( + (currentInterval->position + currentInterval->length) - pos); + } + if (currentInterval->length > longestInterval) + longestInterval = currentInterval->length; + intervals = + addInterval(intervals, {currentInterval->position, currentInterval->end}); +} + +void TrackMetrics::pauseInterval(uint64_t pos, bool pause) { + // end Interval + if (pause) { + currentInterval->length = + this->ctx->timeProvider->getSyncedTimestamp() - currentInterval->start; + currentInterval->end = currentInterval->position + currentInterval->length; + totalAmountPlayed += currentInterval->length; + // add skipped time + if (pos != 0) { + if (pos > currentInterval->position + currentInterval->length) + skipped_forward.add( + pos - (currentInterval->position + currentInterval->length)); + else + skipped_backward.add( + (currentInterval->position + currentInterval->length) - pos); + } + if (currentInterval->length > longestInterval) + longestInterval = currentInterval->length; + intervals = addInterval(intervals, + {currentInterval->position, currentInterval->end}); + } else { + currentInterval = std::make_shared( + this->ctx->timeProvider->getSyncedTimestamp(), pos); + } +} + +uint64_t TrackMetrics::getPosition(bool paused) { + return (currentInterval->position + + (paused ? currentInterval->length + : (this->ctx->timeProvider->getSyncedTimestamp() - + currentInterval->start))); +} + +void TrackMetrics::startTrack() { + trackHeaderTime = this->ctx->timeProvider->getSyncedTimestamp(); + audioKeyTime = trackHeaderTime - timestamp; +} + +void TrackMetrics::startTrackDecoding() { + trackHeaderTime = + this->ctx->timeProvider->getSyncedTimestamp() - trackHeaderTime; +} + +void TrackMetrics::startTrackPlaying(uint64_t pos) { + trackLatency = this->ctx->timeProvider->getSyncedTimestamp() - audioKeyTime; + currentInterval = std::make_shared( + this->ctx->timeProvider->getSyncedTimestamp(), pos); +} + +void TrackMetrics::endTrack() { + endInterval(0); + for (const auto& interval : intervals) + totalMsOfPlayedTrack += interval.second - interval.first; + totalAmountOfPlayTime = + this->ctx->timeProvider->getSyncedTimestamp() - timestamp; +} + +void TrackMetrics::newPosition(uint64_t pos) { + if (pos == currentInterval->position + currentInterval->length) + return; + endInterval(pos); + currentInterval = std::make_shared( + this->ctx->timeProvider->getSyncedTimestamp(), pos); +} + +std::string PlaybackMetrics::get_source_from_context() { + if (context_uri != "") { + if (context_uri.find("playlist") != std::string::npos) + return "playlist"; + else if (context_uri.find("collection") != std::string::npos) + return "your_library"; + else if (context_uri.find("artist") != std::string::npos) + return "artist"; + else if (context_uri.find("album") != std::string::npos) + return "album"; + else if (context_uri.find("track") != std::string::npos) + return "track"; + } + return ""; +} +std::string PlaybackMetrics::get_end_source() { + end_source = get_source_from_context(); + return end_source; +} +std::vector PlaybackMetrics::sendEvent( + std::shared_ptr track) { + std::string data; + std::vector msg; + CSPOT_LOG(debug, "Sending playbackend event"); + std::string requestUrl = "hm://event-service/v1/events"; + + append(&msg, "12"); + append(&msg, "45"); + append(&msg, std::to_string(seqNum++)); + append(&msg, this->ctx->config.deviceId); + append(&msg, track->identifier); //PLAYBACKiD + append(&msg, "00000000000000000000000000000000"); //parent_playback_id + append(&msg, start_source); + append( + &msg, + reason_text[(uint8_t)start_reason]); //remote when taken over by anyone + append( + &msg, + end_source == "" + ? get_end_source() + : end_source); //free-tier-artist / playlist / your_library .com.spotify.gaia / artist + append(&msg, + reason_text[(uint8_t)end_reason]); //remote when taken over of anyone + append( + &msg, + std::to_string( + track + ->written_bytes)); //@librespot usually the same size as track->size, if shifted forward, usually shorter, if shifted backward, usually bigger + append(&msg, std::to_string(track->trackMetrics->track_size)); //in bytes + append( + &msg, + std::to_string( + track->trackMetrics + ->totalAmountOfPlayTime)); //total millis from start to end (sometimes a little longer than millis_played) pause has no influence + append(&msg, + std::to_string( + track->trackMetrics->totalAmountPlayed)); //total millis played + append(&msg, + std::to_string(track->trackInfo.duration)); //track duration in millis + append( + &msg, + std::to_string( + track->trackMetrics + ->trackHeaderTime)); //total time of decrypting? often 3 or 4 when nothing played -1 + append(&msg, "0"); // fadeoverlapp? usually 0, but fading is set on + append( + &msg, + "0"); // librespot says, could bee that the first value shows if it is the first played song, usually 0 + append(&msg, "0"); //?? usually 0 + append(&msg, "0"); //?? usually 0 + append(&msg, std::to_string(track->trackMetrics->skipped_backward + .count)); //total times skipped backward + append(&msg, + std::to_string(track->trackMetrics->skipped_backward + .amount)); //total amount of time skipped backward + append(&msg, std::to_string(track->trackMetrics->skipped_forward + .count)); //total times skipped forward + append(&msg, + std::to_string(track->trackMetrics->skipped_forward + .amount)); //total amount of time skipped forward + append( + &msg, + std::to_string( + track->trackMetrics + ->trackLatency)); //randomNumber; biggest value so far 260, usually biggert than 1 //spotify says play latency + append(&msg, "-1"); // usually -1, if paused positive, probablly in seconds + append(&msg, "context"); + append(&msg, std::to_string( + track->trackMetrics + ->audioKeyTime)); //time to get the audiokey? usually -1 + append(&msg, "0"); // usually 0 + append(&msg, "1"); // @librespot audioKey preloaded? usually positive (1) + append(&msg, "0"); //?? usually 0 + append( + &msg, + "0"); //?? usually bigger than 0, if startup(not playing) or takenover "0" + append( + &msg, + "1"); // usually 1 , if taken over 0, if player took over not from the start 0 + append(&msg, + std::to_string( + track->trackMetrics->longestInterval)); //length longest interval + append( + &msg, + std::to_string( + track->trackMetrics + ->totalMsOfPlayedTrack)); //total time since start total millis of song played + append(&msg, "0"); //?? usually 0 + append( + &msg, + "320000"); //CONFIG_CSPOT_AUDIO_FORMAT ? CONFIG_CSPOT_AUDIO_FORMAT == 2 ? "320000" : "160000" : "96000"); // bitrate + append(&msg, context_uri); + append(&msg, "vorbis"); + append( + &msg, + track->trackInfo + .trackId); // sometimes, when commands come from outside, or else, this value is something else and the following one is the gid + append(&msg, ""); + append(&msg, "0"); //?? usually 0 + append(&msg, + std::to_string(track->trackMetrics + ->timestamp)); // unix timestamp when track started + append(&msg, "0"); //?? usually 0 + append(&msg, track->ref.provider); + append( + &msg, + (end_source == "playlist" || end_source == "your_library") + ? "your_library" + : "search"); //std::to_string(this->ctx->referrerIdentifier));//your_library:lybrary_header / autoplay:afterplaylist / search:found in search / find /home:found in home + append( + &msg, + "xpui_2024-05-31_1717155884878_"); //xpui_2024-05-31_1717155884878_ xpui_ + date of version(update) + _ + unix_timestamp probably of update //empty if autoplay + append(&msg, "com.spotify"); + append( + &msg, + "none"); //"transition" : gapless if song ended beforehand inside player + append(&msg, "none"); + append( + &msg, + "local"); // @librespot lastCommandSentByDeviceId , usually"local", if orderd from outside last command ident last comment ident from frame.state + append(&msg, "na"); + append(&msg, "none"); + append( + &msg, + ""); // 3067b220-9721-4489-93b4-118dd3a59b7b //page-instance-id // changing , if radio / autoplay empty + append( + &msg, + ""); // 054dfc5a-0108-4971-b8de-1fd95070e416 //interaction_id // stays still , if radio / autoplay capped + append(&msg, ""); + append(&msg, "5003900000000146"); + append(&msg, ""); + for (int i = 0; i < track->ref.full_metadata_count; i++) + if (strcmp(track->ref.metadata[i].key, "decision_id") == 0) { + append(&msg, track->ref.metadata[i].value); + goto appended_decision_id; + } + append( + &msg, + ""); // decision_id ssp~061a6236e23e1a9847bd9b6ad4cd942eac8d //allways the same , only when radio? / autoplay +appended_decision_id:; + append(&msg, ""); + append(&msg, "0"); //?? usually 0 + append(&msg, "0"); //?? usually 0 + + if (end_reason == END_PLAY) + start_reason = nested_reason; + else + start_reason = end_reason; + start_source = end_source; + +#ifndef CONFIG_HIDDEN + auto responseLambda = [=](MercurySession::Response res) { + }; + + auto parts = MercurySession::DataParts({msg}); + // Execute the request + //ctx->session->execute(MercurySession::RequestType::POST, requestUrl, + // responseLambda, parts); +#endif + return msg; +} \ No newline at end of file diff --git a/cspot/src/LoginBlob.cpp b/cspot/src/LoginBlob.cpp index 62c9df14..31c9d8a6 100644 --- a/cspot/src/LoginBlob.cpp +++ b/cspot/src/LoginBlob.cpp @@ -4,6 +4,7 @@ #include // for initializer_list #include "BellLogger.h" // for AbstractLogger +#include "BellUtils.h" // for getMacAddress #include "ConstantParameters.h" // for brandName, cspot, protoc... #include "Logger.h" // for CSPOT_LOG #include "protobuf/authentication.pb.h" // for AuthenticationType_AUTHE... @@ -15,13 +16,35 @@ #include "nlohmann/json_fwd.hpp" // for json #endif +#include //(for generating unique device id) + using namespace cspot; +std::string sha1_digest(const std::vector& message) { + std::vector digest(20); // SHA1 digest size (160 bits) + mbedtls_sha1_context sha1Context; + + mbedtls_sha1_init(&sha1Context); + mbedtls_sha1_starts(&sha1Context); + mbedtls_sha1_update(&sha1Context, message.data(), message.size()); + mbedtls_sha1_finish(&sha1Context, digest.data()); + mbedtls_sha1_free(&sha1Context); + + // Convert digest to a hex string + std::ostringstream oss; + for (const auto& byte : digest) { + oss << std::hex << std::setw(2) << std::setfill('0') + << static_cast(byte); + } + + return oss.str(); // Return the hex string +} + LoginBlob::LoginBlob(std::string name) { - char hash[32]; - sprintf(hash, "%016zu", std::hash{}(name)); - // base is 142137fd329622137a14901634264e6f332e2411 - this->deviceId = std::string("142137fd329622137a149016") + std::string(hash); + std::string mac_string = bell::getMacAddress(); + CSPOT_LOG(info, "Mac-address : %s", mac_string.c_str()); + std::vector mac(mac_string.begin(), mac_string.end()); + this->deviceId = sha1_digest(mac); this->crypto = std::make_unique(); this->name = name; diff --git a/cspot/src/MercurySession.cpp b/cspot/src/MercurySession.cpp index 7aafbb76..2dc3e782 100644 --- a/cspot/src/MercurySession.cpp +++ b/cspot/src/MercurySession.cpp @@ -18,74 +18,125 @@ #include "ShannonConnection.h" // for ShannonConnection #include "TimeProvider.h" // for TimeProvider #include "Utils.h" // for extract, pack, hton64 +#include "WrappedSemaphore.h" using namespace cspot; +template +T extractData(const std::vector& data, size_t& pos) { + static_assert(std::is_integral::value, + "extractData only supports integral types"); + + // Check that we have enough bytes to extract + if (pos + sizeof(T) > data.size()) { + throw std::out_of_range("Not enough data to extract"); + } + + T value; + memcpy(&value, &data[pos], sizeof(T)); + pos += sizeof(T); + + // Convert to host byte order based on the size of T + if constexpr (sizeof(T) == 2) { + return ntohs(value); + } else if constexpr (sizeof(T) == 4) { + return ntohl(value); + } else if constexpr (sizeof(T) == 8) { + return hton64( + value); // Assuming you have defined `hton64` similarly to `htonl` for 64-bit values + } else { + return 0; // static_assert(false, "Unsupported type size for extractData"); + } +} + MercurySession::MercurySession(std::shared_ptr timeProvider) - : bell::Task("mercury_dispatcher", 4 * 1024, 3, 1) { + : bell::Task("mercury_dispatcher", 8 * 1024, 3, + 1) { //double the size for reconnecting + responseSemaphore = std::make_shared(); this->timeProvider = timeProvider; } MercurySession::~MercurySession() { + this->responseSemaphore->give(); std::scoped_lock lock(this->isRunningMutex); } void MercurySession::runTask() { - isRunning = true; + isRunning.store(true); std::scoped_lock lock(this->isRunningMutex); - this->executeEstabilishedCallback = true; - while (isRunning) { - cspot::Packet packet = {}; - try { - packet = shanConn->recvPacket(); - CSPOT_LOG(info, "Received packet, command: %d", packet.command); - if (static_cast(packet.command) == RequestType::PING) { - timeProvider->syncWithPingPacket(packet.data); - - this->lastPingTimestamp = timeProvider->getSyncedTimestamp(); - this->shanConn->sendPacket(0x49, packet.data); - } else { - this->packetQueue.push(packet); - } - } catch (const std::runtime_error& e) { - CSPOT_LOG(error, "Error while receiving packet: %s", e.what()); - failAllPending(); - - if (!isRunning) - return; - - reconnect(); - continue; + while (isRunning) { + if (!processPackets()) { + handleReconnection(); } } } -void MercurySession::reconnect() { - isReconnecting = true; - +bool MercurySession::processPackets() { try { - this->conn = nullptr; - this->shanConn = nullptr; - - this->connectWithRandomAp(); - this->authenticate(this->authBlob); - - CSPOT_LOG(info, "Reconnection successful"); - - BELL_SLEEP_MS(100); + cspot::Packet packet = shanConn->recvPacket(); + CSPOT_LOG(info, "Received packet, command: %d", packet.command); + if (static_cast(packet.command) == RequestType::PING) { + timeProvider->syncWithPingPacket(packet.data); + + this->lastPingTimestamp = timeProvider->getSyncedTimestamp(); + this->shanConn->sendPacket(0x49, packet.data); + } else if (packet.data.size()) { + std::unique_lock lock(queueMutex); + this->packetQueue.push_back(packet); + lock.unlock(); // Optional, the destructor will unlock it + this->responseSemaphore->give(); + } + return true; + } catch (const std::runtime_error& e) { + CSPOT_LOG(error, "Error while receiving packet: %s", e.what()); + failAllPending(); // Fail all pending requests + return false; + } catch (const std::exception& e) { + CSPOT_LOG(error, "Unexpected exception: %s", e.what()); + failAllPending(); // Fail all pending requests + return false; + } catch (...) { + CSPOT_LOG(error, "Unknown error occurred while receiving packet."); + failAllPending(); // Fail all pending requests + return false; + } +} - lastPingTimestamp = timeProvider->getSyncedTimestamp(); - isReconnecting = false; +void MercurySession::handleReconnection() { + if (isReconnecting) + return; - this->executeEstabilishedCallback = true; - } catch (...) { - CSPOT_LOG(error, "Cannot reconnect, will retry in 5s"); - BELL_SLEEP_MS(5000); + isReconnecting = true; + reconnect(); + isReconnecting = false; +} - if (isRunning) { - return reconnect(); +void MercurySession::reconnect() { + while (isRunning) { + try { + this->shanConn = nullptr; + this->conn = nullptr; + this->partials.clear(); + // Reset connections + this->connectWithRandomAp(); + this->authenticate(this->authBlob); + + CSPOT_LOG(info, "Reconnection successful"); + + BELL_SLEEP_MS(100); + + lastPingTimestamp = timeProvider->getSyncedTimestamp(); + isReconnecting = false; + this->executeEstabilishedCallback = true; + return; // Successful connection, exit loop + } catch (...) { + CSPOT_LOG(error, "Cannot reconnect, will retry in 5s"); + BELL_SLEEP_MS(1000); + if (!isRunning) { // Stop retrying if session is not running + return; + } } } } @@ -126,9 +177,9 @@ void MercurySession::unregisterAudioKey(uint32_t sequenceId) { void MercurySession::disconnect() { CSPOT_LOG(info, "Disconnecting mercury session"); - this->isRunning = false; - conn->close(); + isRunning.store(false); std::scoped_lock lock(this->isRunningMutex); + conn->close(); } std::string MercurySession::getCountryCode() { @@ -136,9 +187,13 @@ std::string MercurySession::getCountryCode() { } void MercurySession::handlePacket() { - Packet packet = {}; - - this->packetQueue.wtpop(packet, 200); + this->responseSemaphore->wait(); + std::unique_lock lock(queueMutex); + if (!packetQueue.size()) + return; + Packet packet = std::move(*packetQueue.begin()); + packetQueue.pop_front(); + lock.unlock(); // Optional, the destructor will unlock it if (executeEstabilishedCallback && this->connectionReadyCallback != nullptr) { executeEstabilishedCallback = false; @@ -165,28 +220,34 @@ void MercurySession::handlePacket() { RequestType::AUDIO_KEY_SUCCESS_RESPONSE; this->audioKeyCallbacks[seqId](success, packet.data); } - break; } case RequestType::SEND: case RequestType::SUB: case RequestType::UNSUB: { CSPOT_LOG(debug, "Received mercury packet"); - auto response = this->decodeResponse(packet.data); - if (this->callbacks.count(response.sequenceId) > 0) { - auto seqId = response.sequenceId; - this->callbacks[response.sequenceId](response); - this->callbacks.erase(this->callbacks.find(seqId)); + if (!response.fail) { + if (this->callbacks.count(response.sequenceId)) { + uint64_t tempSequenceId = response.sequenceId; + this->callbacks[response.sequenceId](response); + this->callbacks.erase(this->callbacks.find(tempSequenceId)); + } + pb_release(Header_fields, &response.mercuryHeader); } break; } case RequestType::SUBRES: { auto response = decodeResponse(packet.data); - - auto uri = std::string(response.mercuryHeader.uri); - if (this->subscriptions.count(uri) > 0) { - this->subscriptions[uri](response); + if (!response.fail) { + std::string uri(response.mercuryHeader.uri); + for (const auto& [subUri, callback] : subscriptions) { + if (uri.find(subUri) != std::string::npos) { + callback(response); + break; + } + } + pb_release(Header_fields, &response.mercuryHeader); } break; } @@ -204,43 +265,88 @@ void MercurySession::failAllPending() { it.second(response); } - // Fail all subscriptions - for (auto& it : this->subscriptions) { - it.second(response); - } - // Remove references - this->subscriptions = {}; this->callbacks = {}; } MercurySession::Response MercurySession::decodeResponse( const std::vector& data) { - Response response = {}; - response.parts = {}; - - auto sequenceLength = ntohs(extract(data, 0)); - response.sequenceId = hton64(extract(data, 2)); - - auto partsNumber = ntohs(extract(data, 11)); - - auto headerSize = ntohs(extract(data, 13)); - auto headerBytes = - std::vector(data.begin() + 15, data.begin() + 15 + headerSize); - - auto pos = 15 + headerSize; - while (pos < data.size()) { - auto partSize = ntohs(extract(data, pos)); - - response.parts.push_back(std::vector( - data.begin() + pos + 2, data.begin() + pos + 2 + partSize)); - pos += 2 + partSize; + size_t pos = 0; + auto sequenceLength = extractData(data, pos); + uint64_t sequenceId; + uint8_t flag; + Response resp; + resp.mercuryHeader = Header_init_default; + if (sequenceLength == 2) + sequenceId = extractData(data, pos); + else if (sequenceLength == 4) + sequenceId = extractData(data, pos); + else if (sequenceLength == 8) + sequenceId = extractData(data, pos); + else + return resp; + + flag = (uint8_t)data[pos]; + pos++; + uint16_t parts = extractData(data, pos); + auto partial = std::find_if( + partials.begin(), partials.end(), + [sequenceId](const Response& p) { return p.sequenceId == sequenceId; }); + if (partial == partials.end()) { + if (flag == 2) + return resp; + CSPOT_LOG(debug, + "Creating new Mercury Response, seq: %lli, flags: %i, parts: %i", + sequenceId, flag, parts); + this->partials.push_back(Response()); + partial = partials.end() - 1; + partial->parts = {}; + partial->sequenceId = sequenceId; + } else + CSPOT_LOG(debug, + "Adding to Mercury Response, seq: %lli, flags: %i, parts: %i", + sequenceId, flag, parts); + uint8_t index = 0; + while (parts) { + if (data.size() <= pos) + break; + auto partSize = extractData(data, pos); + if (partial->mercuryHeader.uri == NULL) { + auto headerBytes = std::vector(data.begin() + pos, + data.begin() + pos + partSize); + pbDecode(partial->mercuryHeader, Header_fields, headerBytes); + pb_istream_t stream = + pb_istream_from_buffer(&headerBytes[0], headerBytes.size()); + + // Decode the message + if (pb_decode(&stream, Header_fields, &partial->mercuryHeader) == false) { + pb_release(Header_fields, &partial->mercuryHeader); + partials.erase(partial); + return resp; + } + } else { + if (index >= partial->parts.size()) + partial->parts.push_back(std::vector{}); + partial->parts[index].insert(partial->parts[index].end(), + data.begin() + pos, + data.begin() + pos + partSize); + index++; + } + pos += partSize; + parts--; } + if (flag == static_cast(ResponseFlag::FINAL) && + partial->mercuryHeader.uri != NULL) { + resp = std::move(*partial); + partials.erase(partial); + resp.fail = false; + } + return resp; +} - pbDecode(response.mercuryHeader, Header_fields, headerBytes); - response.fail = false; - - return response; +void MercurySession::addSubscriptionListener(const std::string& uri, + ResponseCallback subscription) { + this->subscriptions.insert({uri, subscription}); } uint64_t MercurySession::executeSubscription(RequestType method, @@ -248,19 +354,19 @@ uint64_t MercurySession::executeSubscription(RequestType method, ResponseCallback callback, ResponseCallback subscription, DataParts& payload) { + while (isReconnecting) + BELL_SLEEP_MS(100); CSPOT_LOG(debug, "Executing Mercury Request, type %s", RequestTypeMap[method].c_str()); // Encode header - pbPutString(uri, tempMercuryHeader.uri); - pbPutString(RequestTypeMap[method], tempMercuryHeader.method); + pb_release(Header_fields, &tempMercuryHeader); + tempMercuryHeader.uri = strdup(uri.c_str()); + tempMercuryHeader.method = strdup(RequestTypeMap[method].c_str()); - tempMercuryHeader.has_method = true; - tempMercuryHeader.has_uri = true; - - // GET and SEND are actually the same. Therefore the override - // The difference between them is only in header's method - if (method == RequestType::GET) { + // Map logical request type to the appropriate wire request type (SEND for POST, GET, PUT) + if (method == RequestType::GET || method == RequestType::POST || + method == RequestType::PUT) { method = RequestType::SEND; } @@ -269,16 +375,40 @@ uint64_t MercurySession::executeSubscription(RequestType method, } auto headerBytes = pbEncode(Header_fields, &tempMercuryHeader); + pb_release(Header_fields, &tempMercuryHeader); + + if (callback != nullptr) + this->callbacks.insert({sequenceId, callback}); - this->callbacks.insert({sequenceId, callback}); + // Prepare the data packet structure: + // [Sequence size] [SequenceId] [0x1] [Payloads number] [Header size] [Header] [Payloads (size + data)] + auto sequenceIdBytes = + prepareSequenceIdPayload(sequenceId, headerBytes, payload); - // Structure: [Sequence size] [SequenceId] [0x1] [Payloads number] - // [Header size] [Header] [Payloads (size + data)] + // Bump sequence ID for the next request + this->sequenceId += 1; + try { + while (isReconnecting) + BELL_SLEEP_MS(100); + this->shanConn->sendPacket( + static_cast::type>(method), + sequenceIdBytes); + } catch (...) { + // @TODO: handle disconnect + } + + return this->sequenceId - 1; +} + +std::vector MercurySession::prepareSequenceIdPayload( + uint64_t sequenceId, const std::vector& headerBytes, + const DataParts& payload) { // Pack sequenceId - auto sequenceIdBytes = pack(hton64(this->sequenceId)); + auto sequenceIdBytes = pack(hton64(sequenceId)); auto sequenceSizeBytes = pack(htons(sequenceIdBytes.size())); + // Initial parts of the packet sequenceIdBytes.insert(sequenceIdBytes.begin(), sequenceSizeBytes.begin(), sequenceSizeBytes.end()); sequenceIdBytes.push_back(0x01); @@ -287,6 +417,7 @@ uint64_t MercurySession::executeSubscription(RequestType method, sequenceIdBytes.insert(sequenceIdBytes.end(), payloadNum.begin(), payloadNum.end()); + // Encode the header size and the header data auto headerSizePayload = pack(htons(headerBytes.size())); sequenceIdBytes.insert(sequenceIdBytes.end(), headerSizePayload.begin(), headerSizePayload.end()); @@ -294,26 +425,14 @@ uint64_t MercurySession::executeSubscription(RequestType method, headerBytes.end()); // Encode all the payload parts - for (int x = 0; x < payload.size(); x++) { - headerSizePayload = pack(htons(payload[x].size())); + for (const auto& part : payload) { + headerSizePayload = pack(htons(part.size())); sequenceIdBytes.insert(sequenceIdBytes.end(), headerSizePayload.begin(), headerSizePayload.end()); - sequenceIdBytes.insert(sequenceIdBytes.end(), payload[x].begin(), - payload[x].end()); - } - - // Bump sequence id - this->sequenceId += 1; - - try { - this->shanConn->sendPacket( - static_cast::type>(method), - sequenceIdBytes); - } catch (...) { - // @TODO: handle disconnect + sequenceIdBytes.insert(sequenceIdBytes.end(), part.begin(), part.end()); } - return this->sequenceId - 1; + return sequenceIdBytes; } uint32_t MercurySession::requestAudioKey(const std::vector& trackId, diff --git a/cspot/src/PlaybackState.cpp b/cspot/src/PlaybackState.cpp deleted file mode 100644 index 72697c2f..00000000 --- a/cspot/src/PlaybackState.cpp +++ /dev/null @@ -1,202 +0,0 @@ -#include "PlaybackState.h" - -#include // for strdup, memcpy, strcpy, strlen -#include // for uint8_t -#include // for free, NULL, realloc, rand -#include -#include // for shared_ptr -#include // for remove_extent_t -#include // for swap - -#include "BellLogger.h" // for AbstractLogger -#include "CSpotContext.h" // for Context::ConfigState, Context (ptr o... -#include "ConstantParameters.h" // for protocolVersion, swVersion -#include "Logger.h" // for CSPOT_LOG -#include "NanoPBHelper.h" // for pbEncode, pbPutString -#include "Packet.h" // for cspot -#include "pb.h" // for pb_bytes_array_t, PB_BYTES_ARRAY_T_A... -#include "pb_decode.h" // for pb_release -#include "protobuf/spirc.pb.h" - -using namespace cspot; - -PlaybackState::PlaybackState(std::shared_ptr ctx) { - this->ctx = ctx; - innerFrame = {}; - remoteFrame = {}; - - // Prepare callbacks for decoding of remote frame track data - remoteFrame.state.track.funcs.decode = &TrackReference::pbDecodeTrackList; - remoteFrame.state.track.arg = &remoteTracks; - - innerFrame.ident = strdup(ctx->config.deviceId.c_str()); - innerFrame.protocol_version = strdup(protocolVersion); - - // Prepare default state - innerFrame.state.has_position_ms = true; - innerFrame.state.position_ms = 0; - - innerFrame.state.status = PlayStatus_kPlayStatusStop; - innerFrame.state.has_status = true; - - innerFrame.state.position_measured_at = 0; - innerFrame.state.has_position_measured_at = true; - - innerFrame.state.shuffle = false; - innerFrame.state.has_shuffle = true; - - innerFrame.state.repeat = false; - innerFrame.state.has_repeat = true; - - innerFrame.device_state.sw_version = strdup(swVersion); - - innerFrame.device_state.is_active = false; - innerFrame.device_state.has_is_active = true; - - innerFrame.device_state.can_play = true; - innerFrame.device_state.has_can_play = true; - - innerFrame.device_state.volume = ctx->config.volume; - innerFrame.device_state.has_volume = true; - - innerFrame.device_state.name = strdup(ctx->config.deviceName.c_str()); - - // Prepare player's capabilities - addCapability(CapabilityType_kCanBePlayer, 1); - addCapability(CapabilityType_kDeviceType, 4); - addCapability(CapabilityType_kGaiaEqConnectId, 1); - addCapability(CapabilityType_kSupportsLogout, 0); - addCapability(CapabilityType_kSupportsPlaylistV2, 1); - addCapability(CapabilityType_kIsObservable, 1); - addCapability(CapabilityType_kVolumeSteps, 64); - addCapability(CapabilityType_kSupportedContexts, -1, - std::vector({"album", "playlist", "search", - "inbox", "toplist", "starred", - "publishedstarred", "track"})); - addCapability(CapabilityType_kSupportedTypes, -1, - std::vector( - {"audio/track", "audio/episode", "audio/episode+track"})); - innerFrame.device_state.capabilities_count = 8; -} - -PlaybackState::~PlaybackState() { - pb_release(Frame_fields, &innerFrame); - pb_release(Frame_fields, &remoteFrame); -} - -void PlaybackState::setPlaybackState(const PlaybackState::State state) { - switch (state) { - case State::Loading: - // Prepare the playback at position 0 - innerFrame.state.status = PlayStatus_kPlayStatusPause; - innerFrame.state.position_ms = 0; - innerFrame.state.position_measured_at = - ctx->timeProvider->getSyncedTimestamp(); - break; - case State::Playing: - innerFrame.state.status = PlayStatus_kPlayStatusPlay; - innerFrame.state.position_measured_at = - ctx->timeProvider->getSyncedTimestamp(); - break; - case State::Stopped: - break; - case State::Paused: - // Update state and recalculate current song position - innerFrame.state.status = PlayStatus_kPlayStatusPause; - uint32_t diff = ctx->timeProvider->getSyncedTimestamp() - - innerFrame.state.position_measured_at; - this->updatePositionMs(innerFrame.state.position_ms + diff); - break; - } -} - -void PlaybackState::syncWithRemote() { - innerFrame.state.context_uri = (char*)realloc( - innerFrame.state.context_uri, strlen(remoteFrame.state.context_uri) + 1); - - strcpy(innerFrame.state.context_uri, remoteFrame.state.context_uri); - - innerFrame.state.has_playing_track_index = true; - innerFrame.state.playing_track_index = remoteFrame.state.playing_track_index; -} - -bool PlaybackState::isActive() { - return innerFrame.device_state.is_active; -} - -void PlaybackState::setActive(bool isActive) { - innerFrame.device_state.is_active = isActive; - if (isActive) { - innerFrame.device_state.became_active_at = - ctx->timeProvider->getSyncedTimestamp(); - innerFrame.device_state.has_became_active_at = true; - } -} - -void PlaybackState::updatePositionMs(uint32_t position) { - innerFrame.state.position_ms = position; - innerFrame.state.position_measured_at = - ctx->timeProvider->getSyncedTimestamp(); -} - -void PlaybackState::setVolume(uint32_t volume) { - innerFrame.device_state.volume = volume; - ctx->config.volume = volume; -} - -bool PlaybackState::decodeRemoteFrame(std::vector& data) { - pb_release(Frame_fields, &remoteFrame); - - remoteTracks.clear(); - - pbDecode(remoteFrame, Frame_fields, data); - - return true; -} - -std::vector PlaybackState::encodeCurrentFrame(MessageType typ) { - // Prepare current frame info - innerFrame.version = 1; - innerFrame.seq_nr = this->seqNum; - innerFrame.typ = typ; - innerFrame.state_update_id = ctx->timeProvider->getSyncedTimestamp(); - innerFrame.has_version = true; - innerFrame.has_seq_nr = true; - innerFrame.recipient_count = 0; - innerFrame.has_state = true; - innerFrame.has_device_state = true; - innerFrame.has_typ = true; - innerFrame.has_state_update_id = true; - - this->seqNum += 1; - - return pbEncode(Frame_fields, &innerFrame); -} - -// Wraps messy nanopb setters. @TODO: find a better way to handle this -void PlaybackState::addCapability(CapabilityType typ, int intValue, - std::vector stringValue) { - innerFrame.device_state.capabilities[capabilityIndex].has_typ = true; - this->innerFrame.device_state.capabilities[capabilityIndex].typ = typ; - - if (intValue != -1) { - this->innerFrame.device_state.capabilities[capabilityIndex].intValue[0] = - intValue; - this->innerFrame.device_state.capabilities[capabilityIndex].intValue_count = - 1; - } else { - this->innerFrame.device_state.capabilities[capabilityIndex].intValue_count = - 0; - } - - for (int x = 0; x < stringValue.size(); x++) { - pbPutString(stringValue[x], - this->innerFrame.device_state.capabilities[capabilityIndex] - .stringValue[x]); - } - - this->innerFrame.device_state.capabilities[capabilityIndex] - .stringValue_count = stringValue.size(); - - this->capabilityIndex += 1; -} diff --git a/cspot/src/PlayerContext.cpp b/cspot/src/PlayerContext.cpp new file mode 100644 index 00000000..8f6be6e0 --- /dev/null +++ b/cspot/src/PlayerContext.cpp @@ -0,0 +1,536 @@ +#include "PlayerContext.h" +#include +#include +#include +#include "MercurySession.h" +#include "protobuf/connect.pb.h" // for PutStateRequest, DeviceState, PlayerState... + +#include "BellLogger.h" // for AbstractLogger +#include "Logger.h" // for CSPOT_LOG +#ifdef BELL_ONLY_CJSON +#include "cJSON.h" +#else +#include "nlohmann/json.hpp" // for basic_json<>::object_t, basic_json +#include "nlohmann/json_fwd.hpp" // for json +#endif + +#define METADATA_STRING "metadata" +#define SMART_SHUFFLE_STRING "shuffle.distribution" + +using namespace cspot; +/** + * @brief Create a C string from a JSON object string value. + * + * @param[in] jsonObject The JSON object. + * @param[in] key The key to look up. + * @return The C string or NULL if the key isn't found or the value is empty. + */ +char* PlayerContext::createStringReferenceIfFound( + nlohmann::json::value_type& jsonObject, const char* key) { + auto object = jsonObject.find(key); + if (object != jsonObject.end()) { + std::string value = object.value(); + if (value.size()) + return strdup(value.c_str()); + } + return NULL; +} + +/** + * @brief Retrieve metadata from a JSON object if a key is found. + * + * This function searches for a specified key in a JSON object. If the key is found, + * it creates a metadata entry with the key and its corresponding value. + * + * @param[in] jsonObject The JSON object to search. + * @param[in] key The key to look for in the JSON object. + * @param[out] metadata The metadata entry to populate if the key is found. + * @return True if the key is found and metadata is populated, false otherwise. + */ +bool createMetadataIfFound(nlohmann::json::value_type& jsonObject, + const char* key, + ProvidedTrack_MetadataEntry& metadata) { + // Find the key in the JSON object + auto object = jsonObject.find(key); + + // Check if the key exists in the JSON object + if (object != jsonObject.end()) { + std::string value = object.value(); + + // Populate metadata with the key and its value + metadata = {strdup(key), value.size() ? strdup(value.c_str()) : NULL}; + return true; + } + + // Return false if the key is not found + return false; +} + +template +T getFromJsonObject(nlohmann::json::value_type& jsonObject, const char* key) { + T value; + auto object = jsonObject.find(key); + if (object != jsonObject.end()) + value = object.value(); + return value; +} + +/** + * @brief Query the autoplay service for a context. + * + * This function queries the autoplay service if a context is autoplay-enabled. + * If the context is autoplay-enabled, it resolves the context into a tracklist. + * + * @param[in] metadata_map The metadata to pass to the autoplay service. + * @param[in] responseFunction The function to call with the resolved tracklist. + * @param[in] secondTry If true, use the first track in the tracklist as the context URI + * instead of the context URI from the player state. + */ +// Helper function to split a string by a delimiter +std::vector split(const std::string& s, char delimiter) { + std::vector tokens; + std::string token; + std::istringstream tokenStream(s); + while (std::getline(tokenStream, token, delimiter)) { + tokens.push_back(token); + } + return tokens; +} + +// Helper function to join a vector of strings with a delimiter +std::string join(const std::vector& vec, char delimiter) { + std::ostringstream result; + for (size_t i = 0; i < vec.size(); ++i) { + result << vec[i]; + if (i < vec.size() - 1) { + result << delimiter; + } + } + return result.str(); +} + +// Function to process the next_page_url +char* processNextPageUrl(const std::string& url, size_t trackLimit, + uint64_t* radio_offset) { + const std::string key = "prev_tracks="; + size_t startPos = url.find(key); + if (startPos == std::string::npos) { + return NULL; // No prev_tracks found + } + startPos += key.length(); + + // Find the end of the prev_tracks parameter + size_t endPos = url.find('&', startPos); + std::string prevTracks = (endPos == std::string::npos) + ? url.substr(startPos) + : url.substr(startPos, endPos - startPos); + + // Split, cap, and join + std::vector tracks = split(prevTracks, ','); + if (tracks.size() > trackLimit) { + *radio_offset += tracks.size() - trackLimit; + tracks.erase(tracks.begin(), tracks.end() - trackLimit); + } + std::string newPrevTracks = join(tracks, ','); + + // Rebuild the URL + std::string rebuiltUrl = url.substr(0, startPos) + newPrevTracks + + "&offset=" + std::to_string(*radio_offset); + return strdup(rebuiltUrl.c_str()); +} +void PlayerContext::autoplayQuery( + std::vector> metadata_map, + void (*responseFunction)(void*), bool secondTry) { + if (next_page_url != NULL) + return resolveRadio(metadata_map, responseFunction, next_page_url); + if (playerState->context_uri == NULL) + secondTry = true; + std::string requestUrl = + string_format("hm://autoplay-enabled/query?uri=%s", + secondTry ? tracks->at(0).uri : playerState->context_uri); + CSPOT_LOG(debug, "Querying autoplay: %s", &requestUrl[0]); + auto responseHandler = [this, metadata_map, responseFunction, + secondTry](MercurySession::Response res) { + if (res.fail || !res.parts.size() || !res.parts[0].size()) { + if (!secondTry) + return autoplayQuery(metadata_map, responseFunction, true); + //else + //return responseFunction((void*)radio_offset); + } + std::string resolve_autoplay = + std::string(res.parts[0].begin(), res.parts[0].end()); + std::string requestUrl; + { + if (tracks->back().provider && + (strcmp(tracks->back().provider, "context") == 0 || + playerState->context_uri == NULL)) + requestUrl = string_format( + "hm://radio-apollo/v3/stations/%s?autoplay=true", //&offset=%i", + &resolve_autoplay[0]); //, tracks->back().original_index); + else { + requestUrl = "hm://radio-apollo/v3/tracks/" + + (std::string)tracks->at(0).uri + + "?autoplay=true&count=50&isVideo=false&prev_tracks="; + bool copiedTracks = false; + auto trackRef = + tracks->size() > 50 ? tracks->end() - 50 : tracks->begin(); + while (trackRef != tracks->end()) { + if (trackRef->removed == NULL && //is no demlimiter + (trackRef->uri && strrchr(trackRef->uri, ':'))) { + if (copiedTracks) + requestUrl += ","; + requestUrl += (std::string)(strrchr(trackRef->uri, ':') + 1); + copiedTracks = true; + } + trackRef++; + } + } + resolveRadio(metadata_map, responseFunction, &requestUrl[0]); + } + }; + ctx->session->execute(MercurySession::RequestType::GET, requestUrl, + responseHandler); +} + +void PlayerContext::resolveRadio( + std::vector> metadata_map, + void (*responseFunction)(void*), char* url) { + CSPOT_LOG(debug, "Resolve radio"); + auto responseHandler = [this, metadata_map, + responseFunction](MercurySession::Response res) { + if (res.fail || !res.parts.size()) + return responseFunction((void*)radio_offset); + if (!res.parts[0].size()) + return responseFunction((void*)radio_offset); + // remove old_tracks, keep 5 tracks in memory + if (*index > 5) { + cspot::TrackReference::deleteTracksInRange(tracks, 0, *index - 5); + *index = 4; + } + if (!nlohmann::json::accept(res.parts[0])) { + return responseFunction((void*)radio_offset); + } + auto jsonResult = nlohmann::json::parse(res.parts[0]); + context_uri = jsonResult.value("uri", context_uri); + if (next_page_url != NULL) + free(next_page_url); + + auto urlObject = jsonResult.find("next_page_url"); + if (urlObject != jsonResult.end()) { + next_page_url = processNextPageUrl(urlObject.value(), 100, &radio_offset); + } + + std::vector> metadata = metadata_map; + metadata.push_back(std::make_pair("context_uri", context_uri)); + metadata.push_back(std::make_pair("entity_uri", context_uri)); + metadata.push_back(std::make_pair("iteration", "0")); + metadata.insert(metadata.begin(), + std::make_pair("autoplay.is_autoplay", "true")); + metadata.push_back(std::make_pair("track_player", "audio")); + metadata.push_back( + std::make_pair("actions.skipping_next_past_track", "resume")); + metadata.push_back( + std::make_pair("actions.skipping_prev_past_track", "resume")); + jsonToTracklist(tracks, metadata, jsonResult["tracks"], "autoplay", 0); + radio_offset++; + responseFunction(NULL); + }; + ctx->session->execute(MercurySession::RequestType::GET, url, responseHandler); +} + +static unsigned long distributionToIndex(std::string d) { + return strtoul(&d[d.find("(") + 1], nullptr, 10); +} + +void PlayerContext::createIndexBasedOnTracklist( + std::vector* tracks, nlohmann::json::value_type& json_tracks, + bool shuffle, uint8_t page) { + //create new index + alternative_index.clear(); + std::vector shuffle_index; + bool smart_shuffle = + (json_tracks.at(0).find(METADATA_STRING) == json_tracks.at(0).end() || + json_tracks.at(0).find(METADATA_STRING)->find(SMART_SHUFFLE_STRING) == + json_tracks.at(0).find(METADATA_STRING)->end()) + ? false + : true; + for (int i = 0; i < tracks->size(); i++) { + if (strstr(tracks->at(i).uri, "spotify:delimiter")) { + uint8_t release_offset = 1; + CSPOT_LOG(info, "deleting %i tracks", tracks->size() - (i + 1)); + cspot::TrackReference::deleteTracksInRange(tracks, i + 1, + tracks->size() - 1); + break; + } + } + if (smart_shuffle) + alternative_index = std::vector(json_tracks.size()); + for (int i = 0; i < json_tracks.size(); i++) { + if (smart_shuffle) { + alternative_index[distributionToIndex(json_tracks.at(i) + .find(METADATA_STRING) + ->find(SMART_SHUFFLE_STRING) + ->get()) - + 1] = i; + } else if (!shuffle) + alternative_index.push_back(i); + for (auto& track : *tracks) { + if (track.uri == json_tracks.at(i)["uri"].get_ref()) { + track.original_index = i; + track.page = page; + if (shuffle && !smart_shuffle) + alternative_index.push_back(i); + goto found_track; + } + } + if (shuffle && !smart_shuffle) + shuffle_index.push_back(i); + found_track:; + } + if (shuffle && !smart_shuffle) { + if (shuffle_index.size()) + ctx->rng = std::default_random_engine{ctx->rd()}; + std::shuffle(shuffle_index.begin(), shuffle_index.end(), ctx->rng); + alternative_index.insert(strstr(tracks->back().uri, "spotify:delimiter") + ? alternative_index.end() + : alternative_index.begin(), + shuffle_index.begin(), shuffle_index.end()); + } +} +void jsonToDevice() {} + +uint8_t PlayerContext::jsonToTracklist( + std::vector* tracks, + std::vector> metadata_map, + nlohmann::json::value_type& json_tracks, const char* provider, + uint32_t offset, uint8_t page, bool shuffle, bool preloadedTrack) { + if (offset >= json_tracks.size()) + return 0; + bool radio = (strcmp("autoplay", provider) == 0) ? true : false; + uint8_t copiedTracks = 0; + if (!radio && json_tracks.size() != alternative_index.size()) + createIndexBasedOnTracklist(tracks, json_tracks, shuffle, page); + if (shuffle) { + for (int i = 0; i < alternative_index.size(); i++) + if (alternative_index[i] == offset) { + offset = i; + break; + } + } + if (preloadedTrack) + offset++; + while (tracks->size() < MAX_TRACKS && offset < json_tracks.size()) { + + ProvidedTrack new_track = ProvidedTrack_init_zero; + int64_t index_ = radio ? offset : alternative_index[offset]; + if (index_ >= json_tracks.size() || index_ < 0) { + offset++; + continue; + } + auto track = json_tracks.at(index_); + new_track.uri = createStringReferenceIfFound(track, "uri"); + new_track.uid = createStringReferenceIfFound(track, "uid"); + new_track.provider = strdup(provider); + uint8_t metadata_offset = 0; + for (auto metadata : metadata_map) { + new_track.metadata[metadata_offset].key = strdup(metadata.first.c_str()); + new_track.metadata[metadata_offset].value = + strdup(metadata.second.c_str()); + metadata_offset++; + } + auto json_metadata = track.find(METADATA_STRING); + if (json_metadata != track.end()) { + metadata_offset += createMetadataIfFound( + *json_metadata, "decision_id", new_track.metadata[metadata_offset]); + //metadata_offset += createMetadataIfFound(*json_metadata, "provider", new_track.metadata[metadata_offset]); + new_track.metadata_count = metadata_offset; + for (auto metadata : track.at("metadata").items()) { + if (metadata.key() != "decision_id" && + metadata.key() != "is_promotional" && + metadata.key() != "is_explicit") { + new_track.metadata[metadata_offset].key = + strdup(metadata.key().c_str()); + new_track.metadata[metadata_offset].value = + strdup(((std::string)metadata.value()).c_str()); + metadata_offset++; + } + } + } + new_track.full_metadata_count = metadata_offset; + if (!radio) + new_track.metadata_count = metadata_offset; + new_track.original_index = index_; + new_track.page = page; + tracks->push_back(new_track); + copiedTracks++; + offset++; + } + if (offset == json_tracks.size() && !radio) { + ProvidedTrack new_track = ProvidedTrack_init_zero; + new_track.uri = strdup("spotify:delimiter"); + new_track.uid = strdup("delimiter0"); + new_track.provider = strdup(provider); + new_track.removed = strdup((std::string(provider) + "/delimiter").c_str()); + new_track.metadata[0] = {strdup("hidden"), strdup("true")}; + new_track.metadata[1] = {strdup("actions.skipping_next_past_track"), + strdup("resume")}; + new_track.metadata[2] = {strdup("actions.advancing_past_track"), + strdup("resume")}; + new_track.metadata_count = 3; + new_track.full_metadata_count = 3; + tracks->push_back(new_track); + CSPOT_LOG(debug, "Adding delimiter to tracklist"); + } + return copiedTracks; +} + +void PlayerContext::resolveTracklist( + std::vector> metadata_map, + void (*responseFunction)(void*), bool changed_state, + bool trackIsPartOfContext) { + if (changed_state) { + //new Playlist/context was loaded, check if there is a delimiter in tracklist and if, delete all after + for (int i = 0; i < tracks->size(); i++) { + if (tracks->at(i).uri && strstr(tracks->at(i).uri, "spotify:delimiter")) { + CSPOT_LOG(debug, + "Deleting all tracks after delimiter, current tracklist " + "size: %i, index: %i", + tracks->size(), i); + cspot::TrackReference::deleteTracksInRange(tracks, i, + tracks->size() - 1); + break; + } + } + } + //if current track's provider is autoplay, skip loading the tracklist and query autoplay + if (playerState->track.provider == NULL || + strcmp(playerState->track.provider, "autoplay") == 0) { + return autoplayQuery(metadata_map, responseFunction); + } else + radio_offset = 0; + if (playerState->context_uri == NULL) + return responseFunction((void*)radio_offset); + //if last track was no radio track, resolve tracklist + + std::string requestUrl = "hm://context-resolve/v1/%s"; + if (playerState->options.shuffling_context && + playerState->options.context_enhancement_count) + requestUrl = string_format(requestUrl, &playerState->context_url[10]); + else + requestUrl = string_format(requestUrl, playerState->context_uri); + CSPOT_LOG(debug, "Resolve context, url: %s", &requestUrl[0]); + + auto responseHandler = [this, metadata_map, responseFunction, changed_state, + trackIsPartOfContext](MercurySession::Response res) { + if (res.fail || !res.parts.size()) + return responseFunction((void*)radio_offset); + if (!res.parts[0].size()) + return responseFunction((void*)radio_offset); + auto jsonResult = nlohmann::json::parse(res.parts[0]); + uint8_t pageIndex = 0; + uint32_t offset = 0; + bool smartShuffledTrack = false, foundTrack = false; + std::vector::iterator trackref = tracks->begin(); + if (tracks->size()) { + // do all the look up magic before deleting tracks + trackref = tracks->end() - 1; + //if last track in tracklist was a queued track/delimiter, try to look for a normal track as lookup reference + while (trackref != tracks->begin()) { + smartShuffledTrack = false; + if (trackref->removed == NULL) { // is not a delimiter + if (strcmp(trackref->provider, "context") == 0) { + for (int i = 0; i < trackref->full_metadata_count; i++) { + if (strcmp(trackref->metadata[i].key, "provider") == 0 && + !playerState->options + .context_enhancement_count) { //was a smart_shuffle-track, but smart_shuffle is no more + smartShuffledTrack = true; + break; + } + } + break; + } + } + CSPOT_LOG(debug, "trackref: %s", trackref->uri); + trackref--; + } + if (trackref->removed != NULL) { + if (tracks->size() == 1) + return responseFunction((void*)radio_offset); + else + return autoplayQuery(metadata_map, responseFunction); + } + CSPOT_LOG(debug, "Last track in tracklist: %s", trackref->uri); + if (!smartShuffledTrack || + playerState->options.context_enhancement_count) { + for (pageIndex = 0; pageIndex < jsonResult["pages"].size(); + pageIndex++) { + offset = 0; + for (auto track : jsonResult["pages"][pageIndex]["tracks"]) { + if (strcmp(track["uri"].get().c_str(), + trackref->uri) == 0) { + foundTrack = true; + break; + } + //??if(foundTrack) break; + if (foundTrack) + break; + offset++; + } + if (foundTrack) + break; + } + //if trackreference was found + } + } + if (!foundTrack) { + pageIndex = 0; + offset = 0; + } + CSPOT_LOG(debug, "Context at page %i, offset %i", pageIndex, offset); + //delete tracks ? + //if tracklist is in a new state, create index based on tracklist + if (changed_state) { + createIndexBasedOnTracklist( + tracks, jsonResult["pages"][pageIndex]["tracks"], + playerState->options.shuffling_context, pageIndex); + + //if smart_shuffle is tur + if (playerState->options.shuffling_context) { + if (alternative_index[trackref - tracks->begin()] != offset) { + for (auto& index_ : alternative_index) + if (index_ == offset) { + index_ = alternative_index[trackref - tracks->begin()]; + alternative_index[trackref - tracks->begin()] = offset; + break; + } + } + } + } + + // remove played tracks, keep 5 tracks in memory + if (*index > 5) { + cspot::TrackReference::deleteTracksInRange(tracks, 0, *index - 5); + *index = 4; + } + CSPOT_LOG( + debug, + "Current tracklist size: %i, loading tracklist from page %i, offset %i", + tracks->size(), pageIndex, offset); + + offset = jsonToTracklist( + tracks, metadata_map, jsonResult["pages"][pageIndex]["tracks"], + "context", offset, pageIndex, playerState->options.shuffling_context, + foundTrack); + if (offset > 1) { + CSPOT_LOG(debug, "Tracklist populated with %i tracks", offset); + return responseFunction(NULL); + } else if (playerState->options.repeating_context) { + jsonToTracklist(tracks, metadata_map, + jsonResult["pages"][pageIndex]["tracks"], "context", 0, + pageIndex, playerState->options.shuffling_context); + } else + return autoplayQuery(metadata_map, responseFunction); + }; + ctx->session->execute(MercurySession::RequestType::GET, requestUrl, + responseHandler); +} \ No newline at end of file diff --git a/cspot/src/Session.cpp b/cspot/src/Session.cpp index 74bd0633..8700d33a 100644 --- a/cspot/src/Session.cpp +++ b/cspot/src/Session.cpp @@ -74,8 +74,8 @@ std::vector Session::authenticate(std::shared_ptr blob) { // save auth blob for reconnection purposes authBlob = blob; // prepare authentication request proto - auto data = challenges->prepareAuthPacket(blob->authData, blob->authType, - deviceId, blob->username); + auto data = challenges->prepareAuthPacket( + blob->authData, blob->authType, blob->getDeviceId(), blob->username); // Send login request this->shanConn->sendPacket(LOGIN_REQUEST_COMMAND, data); diff --git a/cspot/src/ShannonConnection.cpp b/cspot/src/ShannonConnection.cpp index ebfe0917..5737dcf4 100644 --- a/cspot/src/ShannonConnection.cpp +++ b/cspot/src/ShannonConnection.cpp @@ -16,7 +16,9 @@ using namespace cspot; ShannonConnection::ShannonConnection() {} -ShannonConnection::~ShannonConnection() {} +ShannonConnection::~ShannonConnection() { + std::scoped_lock lock(this->writeMutex, this->readMutex); +} void ShannonConnection::wrapConnection( std::shared_ptr conn, std::vector& sendKey, diff --git a/cspot/src/SpircHandler.cpp b/cspot/src/SpircHandler.cpp deleted file mode 100644 index 8d8add6a..00000000 --- a/cspot/src/SpircHandler.cpp +++ /dev/null @@ -1,310 +0,0 @@ -#include "SpircHandler.h" - -#include // for uint8_t -#include // for shared_ptr, make_unique, unique_ptr -#include // for remove_extent_t -#include // for move - -#include "BellLogger.h" // for AbstractLogger -#include "CSpotContext.h" // for Context::ConfigState, Context (ptr only) -#include "Logger.h" // for CSPOT_LOG -#include "MercurySession.h" // for MercurySession, MercurySession::Response -#include "NanoPBHelper.h" // for pbDecode -#include "Packet.h" // for cspot -#include "PlaybackState.h" // for PlaybackState, PlaybackState::State -#include "TrackPlayer.h" // for TrackPlayer -#include "TrackQueue.h" -#include "TrackReference.h" // for TrackReference -#include "Utils.h" // for stringHexToBytes -#include "pb_decode.h" // for pb_release -#include "protobuf/spirc.pb.h" // for Frame, State, Frame_fields, MessageTy... - -using namespace cspot; - -SpircHandler::SpircHandler(std::shared_ptr ctx) { - this->playbackState = std::make_shared(ctx); - this->trackQueue = std::make_shared(ctx, playbackState); - - auto EOFCallback = [this]() { - if (trackQueue->isFinished()) { - sendEvent(EventType::DEPLETED); - } - }; - - auto trackLoadedCallback = [this](std::shared_ptr track, - bool paused = false) { - playbackState->setPlaybackState(paused ? PlaybackState::State::Paused - : PlaybackState::State::Playing); - playbackState->updatePositionMs(track->requestedPosition); - - this->notify(); - - // Send playback start event, pause/unpause per request - sendEvent(EventType::PLAYBACK_START, (int)track->requestedPosition); - sendEvent(EventType::PLAY_PAUSE, paused); - }; - - this->ctx = ctx; - this->trackPlayer = std::make_shared( - ctx, trackQueue, EOFCallback, trackLoadedCallback); - - // Subscribe to mercury on session ready - ctx->session->setConnectedHandler([this]() { this->subscribeToMercury(); }); -} - -void SpircHandler::subscribeToMercury() { - auto responseLambda = [this](MercurySession::Response& res) { - if (res.fail) - return; - - sendCmd(MessageType_kMessageTypeHello); - CSPOT_LOG(debug, "Sent kMessageTypeHello!"); - - // Assign country code - this->ctx->config.countryCode = this->ctx->session->getCountryCode(); - }; - auto subscriptionLambda = [this](MercurySession::Response& res) { - if (res.fail) - return; - CSPOT_LOG(debug, "Received subscription response"); - - this->handleFrame(res.parts[0]); - }; - - ctx->session->executeSubscription( - MercurySession::RequestType::SUB, - "hm://remote/user/" + ctx->config.username + "/", responseLambda, - subscriptionLambda); -} - -void SpircHandler::loadTrackFromURI(const std::string& uri) {} - -void SpircHandler::notifyAudioEnded() { - playbackState->updatePositionMs(0); - notify(); - trackPlayer->resetState(true); -} - -void SpircHandler::notifyAudioReachedPlayback() { - int offset = 0; - - // get HEAD track - auto currentTrack = trackQueue->consumeTrack(nullptr, offset); - - // Do not execute when meta is already updated - if (trackQueue->notifyPending) { - trackQueue->notifyPending = false; - - playbackState->updatePositionMs(currentTrack->requestedPosition); - - // Reset position in queued track - currentTrack->requestedPosition = 0; - } else { - trackQueue->skipTrack(TrackQueue::SkipDirection::NEXT, false); - playbackState->updatePositionMs(0); - - // we moved to next track, re-acquire currentTrack again - currentTrack = trackQueue->consumeTrack(nullptr, offset); - } - - this->notify(); - - sendEvent(EventType::TRACK_INFO, currentTrack->trackInfo); -} - -void SpircHandler::updatePositionMs(uint32_t position) { - playbackState->updatePositionMs(position); - notify(); -} - -void SpircHandler::disconnect() { - this->trackQueue->stopTask(); - this->trackPlayer->stop(); - this->ctx->session->disconnect(); -} - -void SpircHandler::handleFrame(std::vector& data) { - // Decode received spirc frame - playbackState->decodeRemoteFrame(data); - - switch (playbackState->remoteFrame.typ) { - case MessageType_kMessageTypeNotify: { - CSPOT_LOG(debug, "Notify frame"); - - // Pause the playback if another player took control - if (playbackState->isActive() && - playbackState->remoteFrame.device_state.is_active) { - CSPOT_LOG(debug, "Another player took control, pausing playback"); - playbackState->setActive(false); - - this->trackPlayer->stop(); - sendEvent(EventType::DISC); - } - break; - } - case MessageType_kMessageTypeSeek: { - this->trackPlayer->seekMs(playbackState->remoteFrame.position); - - playbackState->updatePositionMs(playbackState->remoteFrame.position); - - notify(); - - sendEvent(EventType::SEEK, (int)playbackState->remoteFrame.position); - break; - } - case MessageType_kMessageTypeVolume: - playbackState->setVolume(playbackState->remoteFrame.volume); - this->notify(); - sendEvent(EventType::VOLUME, (int)playbackState->remoteFrame.volume); - break; - case MessageType_kMessageTypePause: - setPause(true); - break; - case MessageType_kMessageTypePlay: - setPause(false); - break; - case MessageType_kMessageTypeNext: - if (nextSong()) { - sendEvent(EventType::NEXT); - } - break; - case MessageType_kMessageTypePrev: - if (previousSong()) { - sendEvent(EventType::PREV); - } - break; - case MessageType_kMessageTypeLoad: { - this->trackPlayer->start(); - - CSPOT_LOG(debug, "Load frame %d!", playbackState->remoteTracks.size()); - - if (playbackState->remoteTracks.size() == 0) { - CSPOT_LOG(info, "No tracks in frame, stopping playback"); - break; - } - - playbackState->setActive(true); - - playbackState->updatePositionMs(playbackState->remoteFrame.position); - playbackState->setPlaybackState(PlaybackState::State::Playing); - - playbackState->syncWithRemote(); - - // Update track list in case we have a new one - trackQueue->updateTracks(playbackState->remoteFrame.state.position_ms, - true); - - this->notify(); - - // Stop the current track, if any - trackPlayer->resetState(); - break; - } - case MessageType_kMessageTypeReplace: { - CSPOT_LOG(debug, "Got replace frame %d", - playbackState->remoteTracks.size()); - playbackState->syncWithRemote(); - - // 1st track is the current one, but update the position - bool cleared = trackQueue->updateTracks( - playbackState->remoteFrame.state.position_ms + - ctx->timeProvider->getSyncedTimestamp() - - playbackState->innerFrame.state.position_measured_at, - false); - - this->notify(); - - // need to re-load all if streaming track is completed - if (cleared) { - sendEvent(EventType::FLUSH); - trackPlayer->resetState(); - } - break; - } - case MessageType_kMessageTypeShuffle: { - CSPOT_LOG(debug, "Got shuffle frame"); - this->notify(); - break; - } - case MessageType_kMessageTypeRepeat: { - CSPOT_LOG(debug, "Got repeat frame"); - this->notify(); - break; - } - default: - break; - } -} - -void SpircHandler::setRemoteVolume(int volume) { - playbackState->setVolume(volume); - notify(); -} - -void SpircHandler::notify() { - this->sendCmd(MessageType_kMessageTypeNotify); -} - -bool SpircHandler::skipSong(TrackQueue::SkipDirection dir) { - bool skipped = trackQueue->skipTrack(dir); - - // Reset track state - trackPlayer->resetState(!skipped); - - // send NEXT or PREV event only when successful - return skipped; -} - -bool SpircHandler::nextSong() { - return skipSong(TrackQueue::SkipDirection::NEXT); -} - -bool SpircHandler::previousSong() { - return skipSong(TrackQueue::SkipDirection::PREV); -} - -std::shared_ptr SpircHandler::getTrackPlayer() { - return this->trackPlayer; -} - -void SpircHandler::sendCmd(MessageType typ) { - // Serialize current player state - auto encodedFrame = playbackState->encodeCurrentFrame(typ); - - auto responseLambda = [=](MercurySession::Response& res) { - }; - auto parts = MercurySession::DataParts({encodedFrame}); - ctx->session->execute(MercurySession::RequestType::SEND, - "hm://remote/user/" + ctx->config.username + "/", - responseLambda, parts); -} -void SpircHandler::setEventHandler(EventHandler handler) { - this->eventHandler = handler; -} - -void SpircHandler::setPause(bool isPaused) { - if (isPaused) { - CSPOT_LOG(debug, "External pause command"); - playbackState->setPlaybackState(PlaybackState::State::Paused); - } else { - CSPOT_LOG(debug, "External play command"); - - playbackState->setPlaybackState(PlaybackState::State::Playing); - } - notify(); - sendEvent(EventType::PLAY_PAUSE, isPaused); -} - -void SpircHandler::sendEvent(EventType type) { - auto event = std::make_unique(); - event->eventType = type; - event->data = {}; - eventHandler(std::move(event)); -} - -void SpircHandler::sendEvent(EventType type, EventData data) { - auto event = std::make_unique(); - event->eventType = type; - event->data = data; - eventHandler(std::move(event)); -} diff --git a/cspot/src/TrackPlayer.cpp b/cspot/src/TrackPlayer.cpp index c96f2ec7..97f4edc1 100644 --- a/cspot/src/TrackPlayer.cpp +++ b/cspot/src/TrackPlayer.cpp @@ -5,13 +5,16 @@ #include // for remove_extent_t #include // for vector, vector<>::value_type -#include "BellLogger.h" // for AbstractLogger -#include "BellUtils.h" // for BELL_SLEEP_MS +#include "BellLogger.h" // for AbstractLogger +#include "BellUtils.h" // for BELL_SLEEP_MS +#include "CSpotContext.h" +#include "EventManager.h" #include "Logger.h" // for CSPOT_LOG #include "Packet.h" // for cspot #include "TrackQueue.h" // for CDNTrackStream, CDNTrackStream::TrackInfo #include "WrappedSemaphore.h" // for WrappedSemaphore +#ifndef CONFIG_BELL_NOCODEC #ifdef BELL_VORBIS_FLOAT #define VORBIS_SEEK(file, position) \ (ov_time_seek(file, (double)position / 1000)) @@ -22,14 +25,17 @@ #define VORBIS_READ(file, buffer, bufferSize, section) \ (ov_read(file, buffer, bufferSize, section)) #endif +#endif namespace cspot { struct Context; struct TrackReference; +class PlaybackMetrics; } // namespace cspot using namespace cspot; +#ifndef CONFIG_BELL_NOCODEC static size_t vorbisReadCb(void* ptr, size_t size, size_t nmemb, TrackPlayer* self) { return self->_vorbisRead(ptr, size, nmemb); @@ -47,17 +53,22 @@ static int vorbisSeekCb(TrackPlayer* self, int64_t offset, int whence) { static long vorbisTellCb(TrackPlayer* self) { return self->_vorbisTell(); } +#endif TrackPlayer::TrackPlayer(std::shared_ptr ctx, std::shared_ptr trackQueue, - EOFCallback eof, TrackLoadedCallback trackLoaded) + TrackEndedCallback onTrackEnd, + TrackChangedCallback onTrackChanged, + bool* repeating_track) : bell::Task("cspot_player", 48 * 1024, 5, 1) { this->ctx = ctx; - this->eofCallback = eof; - this->trackLoaded = trackLoaded; + this->onTrackEnd = onTrackEnd; + this->onTrackChanged = onTrackChanged; this->trackQueue = trackQueue; this->playbackSemaphore = std::make_unique(5); + repeating_track_ = repeating_track; +#ifndef CONFIG_BELL_NOCODEC // Initialize vorbis callbacks vorbisFile = {}; vorbisCallbacks = { @@ -66,6 +77,7 @@ TrackPlayer::TrackPlayer(std::shared_ptr ctx, (decltype(ov_callbacks::close_func))&vorbisCloseCb, (decltype(ov_callbacks::tell_func))&vorbisTellCb, }; +#endif } TrackPlayer::~TrackPlayer() { @@ -78,7 +90,10 @@ void TrackPlayer::start() { if (!isRunning) { isRunning = true; startTask(); - } + this->ctx->playbackMetrics->start_reason = PlaybackMetrics::REMOTE; + this->ctx->playbackMetrics->start_source = "unknown"; + } else + this->ctx->playbackMetrics->end_reason = PlaybackMetrics::END_PLAY; } void TrackPlayer::stop() { @@ -98,11 +113,14 @@ void TrackPlayer::resetState(bool paused) { CSPOT_LOG(info, "Resetting state"); } -void TrackPlayer::seekMs(size_t ms) { - if (inFuture) { +void TrackPlayer::seekMs(size_t ms, bool loading) { +#ifndef CONFIG_BELL_NOCODEC + if (!loading) { // We're in the middle of the next track, so we need to reset the player in order to seek + CSPOT_LOG(info, "Resetting state"); resetState(); } +#endif CSPOT_LOG(info, "Seeking..."); this->pendingSeekPositionMs = ms; @@ -111,19 +129,16 @@ void TrackPlayer::seekMs(size_t ms) { void TrackPlayer::runTask() { std::scoped_lock lock(runningMutex); - std::shared_ptr track, newTrack = nullptr; + std::shared_ptr track = nullptr, newTrack = nullptr; int trackOffset = 0; + size_t tracksPlayed = 1; bool eof = false; bool endOfQueueReached = false; while (isRunning) { - // Ensure we even have any tracks to play - if (!this->trackQueue->hasTracks() || - (!pendingReset && endOfQueueReached && trackQueue->isFinished())) { - this->trackQueue->playableSemaphore->twait(300); - continue; - } + bool properStream = true; + this->trackQueue->playableSemaphore->wait(); // Last track was interrupted, reset to default if (pendingReset) { @@ -141,63 +156,103 @@ void TrackPlayer::runTask() { if (pendingReset) { continue; } - - newTrack = trackQueue->consumeTrack(track, trackOffset); + if (!*repeating_track_ || newTrack == nullptr) + newTrack = trackQueue->consumeTrack(track, trackOffset); if (newTrack == nullptr) { if (trackOffset == -1) { // Reset required track = nullptr; } + CSPOT_LOG(error, "NULLPTR"); BELL_SLEEP_MS(100); continue; } track = newTrack; + this->ctx->playbackMetrics->trackMetrics = track->trackMetrics; inFuture = trackOffset > 0; - + uint8_t retries = 10; + while (track->state != QueuedTrack::State::READY && + track->state != QueuedTrack::State::FAILED && retries-- > 0) { + BELL_SLEEP_MS(100); + CSPOT_LOG(error, "Track in state %i", (int)track->state); + } if (track->state != QueuedTrack::State::READY) { - track->loadedSemaphore->twait(5000); - - if (track->state != QueuedTrack::State::READY) { - CSPOT_LOG(error, "Track failed to load, skipping it"); - this->eofCallback(); - continue; - } + CSPOT_LOG(error, "Track failed to load, skipping it"); + if (track->ref.removed != NULL) + this->onTrackChanged(track, false); + this->onTrackEnd(true); + continue; } - - CSPOT_LOG(info, "Got track ID=%s", track->identifier.c_str()); - + track->playingTrackIndex = tracksPlayed; currentSongPlaying = true; - + track->trackMetrics->startTrack(); + retries = 3; { std::scoped_lock lock(playbackMutex); + bool skipped = 0; currentTrackStream = track->getAudioFile(); - // Open the stream +#ifndef CONFIG_BELL_NOCODEC currentTrackStream->openStream(); - +#else + ssize_t start_offset = 0; + uint8_t* headerBuf = currentTrackStream->openStream(start_offset); + if (start_offset < 0) { + CSPOT_LOG(error, "Track failed to load, skipping it"); + this->onTrackEnd(true); + continue; + } +#endif if (pendingReset || !currentSongPlaying) { continue; } + track->trackMetrics->startTrackDecoding(); + track->trackMetrics->track_size = currentTrackStream->getSize(); - if (trackOffset == 0 && pendingSeekPositionMs == 0) { - this->trackLoaded(track, startPaused); - startPaused = false; - } + this->onTrackChanged(track, true); + startPaused = false; +#ifndef CONFIG_BELL_NOCODEC int32_t r = ov_open_callbacks(this, &vorbisFile, NULL, 0, vorbisCallbacks); +#else + size_t toWrite = start_offset; + while (toWrite) { + size_t written = dataCallback(headerBuf + (start_offset - toWrite), + toWrite, tracksPlayed, 0); + if (written == 0) { + BELL_SLEEP_MS(10); + } + toWrite -= written; + } + track->written_bytes += start_offset; + float duration_lambda = 1.0 * + (currentTrackStream->getSize() - start_offset) / + track->trackInfo.duration; +#endif if (pendingSeekPositionMs > 0) { track->requestedPosition = pendingSeekPositionMs; +#ifdef CONFIG_BELL_NOCODEC + pendingSeekPositionMs = 0; +#endif } + ctx->playbackMetrics->end_reason = PlaybackMetrics::REMOTE; if (track->requestedPosition > 0) { +#ifndef CONFIG_BELL_NOCODEC VORBIS_SEEK(&vorbisFile, track->requestedPosition); +#else + size_t seekPosition = + track->requestedPosition * duration_lambda + start_offset; + currentTrackStream->seek(seekPosition); + skipped = true; +#endif } eof = false; @@ -208,26 +263,74 @@ void TrackPlayer::runTask() { while (!eof && currentSongPlaying) { // Execute seek if needed if (pendingSeekPositionMs > 0) { - uint32_t seekPosition = pendingSeekPositionMs; + track->requestedPosition = pendingSeekPositionMs; + // Seek to the new position +#ifndef CONFIG_BELL_NOCODEC + VORBIS_SEEK(&vorbisFile, track->requestedPosition); +#else + uint32_t seekPosition = track->requestedPosition * duration_lambda + + seekable_callback(tracksPlayed); + currentTrackStream->seek(seekPosition); + skipped = true; +#endif + track->trackMetrics->newPosition(pendingSeekPositionMs); // Reset the pending seek position pendingSeekPositionMs = 0; - - // Seek to the new position - VORBIS_SEEK(&vorbisFile, seekPosition); + this->onTrackChanged(track, false); } - long ret = VORBIS_READ(&vorbisFile, (char*)&pcmBuffer[0], - pcmBuffer.size(), ¤tSection); + long ret = +#ifdef CONFIG_BELL_NOCODEC + this->currentTrackStream->readBytes(&pcmBuffer[0], + pcmBuffer.size()); +#else + VORBIS_READ(&vorbisFile, (char*)&pcmBuffer[0], pcmBuffer.size(), + ¤tSection); +#endif + + if (ret < 0) { + if (retries == 0) { + CSPOT_LOG(error, "Track failed to reload, skipping it"); + currentSongPlaying = false; + properStream = false; + eof = true; + } else { + CSPOT_LOG(error, "An error has occured in the stream %d", ret); + retries--; + CSPOT_LOG(error, "Retries left:%d", retries); +#ifndef CONFIG_BELL_NOCODEC + ov_clear(&vorbisFile); +#endif + size_t pos = this->currentTrackStream->getPosition(); + + this->currentTrackStream = nullptr; + this->currentTrackStream = track->getAudioFile(); - if (ret == 0) { - CSPOT_LOG(info, "EOF"); - // and done :) - eof = true; - } else if (ret < 0) { - CSPOT_LOG(error, "An error has occured in the stream %d", ret); - currentSongPlaying = false; + // Open the stream +#ifndef CONFIG_BELL_NOCODEC + currentTrackStream->openStream(); + int32_t r = + ov_open_callbacks(this, &vorbisFile, NULL, 0, vorbisCallbacks); +#else + ssize_t start_offset = 0; + uint8_t* headerBuf = currentTrackStream->openStream(start_offset); + if (start_offset < 0) { + CSPOT_LOG(error, "Track failed to reload, skipping it"); + currentSongPlaying = false; + properStream = false; + eof = true; + + } else +#endif + this->currentTrackStream->seek(pos); + } } else { + if (ret == 0) { + CSPOT_LOG(info, "EOF"); + // and done :) + eof = true; + } if (this->dataCallback != nullptr) { auto toWrite = ret; @@ -238,19 +341,25 @@ void TrackPlayer::runTask() { // If reset happened during playback, return if (!currentSongPlaying || pendingReset) break; - +#ifdef CONFIG_BELL_NOCODEC + if (skipped) { + // Reset the pending seek position + skipped = false; + } +#endif written = dataCallback(pcmBuffer.data() + (ret - toWrite), - toWrite, track->identifier); - } - if (written == 0) { - BELL_SLEEP_MS(50); + toWrite, tracksPlayed, skipped); } toWrite -= written; } + track->written_bytes += ret; } } } + tracksPlayed++; +#ifndef CONFIG_BELL_NOCODEC ov_clear(&vorbisFile); +#endif CSPOT_LOG(info, "Playing done"); @@ -260,15 +369,17 @@ void TrackPlayer::runTask() { } if (eof) { - if (trackQueue->isFinished()) { + if (this->trackQueue->preloadedTracks.size() <= 1) { endOfQueueReached = true; } - - this->eofCallback(); +#ifdef CONFIG_BELL_NOCODEC + this->onTrackEnd(true); +#endif } } } +#ifndef CONFIG_BELL_NOCODEC size_t TrackPlayer::_vorbisRead(void* ptr, size_t size, size_t nmemb) { if (this->currentTrackStream == nullptr) { return 0; @@ -307,7 +418,14 @@ long TrackPlayer::_vorbisTell() { } return this->currentTrackStream->getPosition(); } +#endif -void TrackPlayer::setDataCallback(DataCallback callback) { +void TrackPlayer::setDataCallback(DataCallback callback, + SeekableCallback seekable_callback, + SeekableCallback spaces_available) { this->dataCallback = callback; +#ifdef CONFIG_BELL_NOCODEC + this->seekable_callback = seekable_callback; + this->spaces_available = spaces_available; +#endif } diff --git a/cspot/src/TrackQueue.cpp b/cspot/src/TrackQueue.cpp index 26ec0a27..98889fcd 100644 --- a/cspot/src/TrackQueue.cpp +++ b/cspot/src/TrackQueue.cpp @@ -5,9 +5,11 @@ #include #include #include +#include #include "AccessKeyFetcher.h" #include "BellTask.h" +#include "BellUtils.h" // for BELL_SLEEP_MS #include "CDNAudioFile.h" #include "CSpotContext.h" #include "HTTPClient.h" @@ -23,6 +25,7 @@ #include "protobuf/metadata.pb.h" using namespace cspot; + namespace TrackDataUtils { bool countryListContains(char* countryList, const char* country) { uint16_t countryList_length = strlen(countryList); @@ -120,19 +123,28 @@ void TrackInfo::loadPbEpisode(Episode* pbEpisode, duration = pbEpisode->duration; } -QueuedTrack::QueuedTrack(TrackReference& ref, - std::shared_ptr ctx, - uint32_t requestedPosition) - : requestedPosition(requestedPosition), ctx(ctx) { +QueuedTrack::QueuedTrack( + ProvidedTrack& ref, std::shared_ptr ctx, + std::shared_ptr playableSemaphore, + int64_t requestedPosition) + : requestedPosition((uint32_t)requestedPosition), ctx(ctx) { + trackMetrics = std::make_shared(ctx, requestedPosition); + this->playableSemaphore = playableSemaphore; this->ref = ref; - - loadedSemaphore = std::make_shared(); - state = State::QUEUED; + this->audioFormat = ctx->config.audioFormat; + if (!strstr(ref.uri, "spotify:delimiter")) { + this->gid = base62Decode(ref.uri); + state = State::QUEUED; + } else { + state = State::FAILED; + playableSemaphore->give(); + } } QueuedTrack::~QueuedTrack() { + //if (state < State::READY) + // playableSemaphore->give(); state = State::FAILED; - loadedSemaphore->give(); if (pendingMercuryRequest != 0) { ctx->session->unregister(pendingMercuryRequest); @@ -141,6 +153,8 @@ QueuedTrack::~QueuedTrack() { if (pendingAudioKeyRequest != 0) { ctx->session->unregisterAudioKey(pendingAudioKeyRequest); } + pb_release(Track_fields, &pbTrack); + pb_release(Episode_fields, &pbEpisode); } std::shared_ptr QueuedTrack::getAudioFile() { @@ -156,15 +170,12 @@ void QueuedTrack::stepParseMetadata(Track* pbTrack, Episode* pbEpisode) { bool canPlay = false; AudioFile* selectedFiles = nullptr; - const char* countryCode = ctx->config.countryCode.c_str(); + const char* countryCode = ctx->session->getCountryCode().c_str(); - if (ref.type == TrackReference::Type::TRACK) { + if (gid.first == SpotifyFileType::TRACK) { CSPOT_LOG(info, "Track name: %s", pbTrack->name); CSPOT_LOG(info, "Track duration: %d", pbTrack->duration); - CSPOT_LOG(debug, "trackInfo.restriction.size() = %d", - pbTrack->restriction_count); - // Check if we can play the track, if not, try alternatives if (TrackDataUtils::doRestrictionsApply( pbTrack->restriction, pbTrack->restriction_count, countryCode)) { @@ -195,9 +206,6 @@ void QueuedTrack::stepParseMetadata(Track* pbTrack, Episode* pbEpisode) { CSPOT_LOG(info, "Episode name: %s", pbEpisode->name); CSPOT_LOG(info, "Episode duration: %d", pbEpisode->duration); - CSPOT_LOG(debug, "episodeInfo.restriction.size() = %d", - pbEpisode->restriction_count); - // Check if we can play the episode if (!TrackDataUtils::doRestrictionsApply(pbEpisode->restriction, pbEpisode->restriction_count, @@ -214,7 +222,7 @@ void QueuedTrack::stepParseMetadata(Track* pbTrack, Episode* pbEpisode) { // Find playable file for (int x = 0; x < filesCount; x++) { CSPOT_LOG(debug, "File format: %d", selectedFiles[x].format); - if (selectedFiles[x].format == ctx->config.audioFormat) { + if (selectedFiles[x].format == audioFormat) { fileId = pbArrayToVector(selectedFiles[x].file_id); break; // If file found stop searching } @@ -223,6 +231,7 @@ void QueuedTrack::stepParseMetadata(Track* pbTrack, Episode* pbEpisode) { if (fileId.size() == 0 && selectedFiles[x].format == AudioFormat_OGG_VORBIS_96) { fileId = pbArrayToVector(selectedFiles[x].file_id); + CSPOT_LOG(info, "Falling back to OGG Vorbis 96kbps"); } } @@ -232,13 +241,10 @@ void QueuedTrack::stepParseMetadata(Track* pbTrack, Episode* pbEpisode) { // no alternatives for song state = State::FAILED; - loadedSemaphore->give(); + playableSemaphore->give(); return; } - - // Assign track identifier identifier = bytesToHexString(fileId); - state = State::KEY_REQUIRED; } @@ -258,12 +264,21 @@ void QueuedTrack::stepLoadAudioFile( std::vector(audioKey.begin() + 4, audioKey.end()); state = State::CDN_REQUIRED; + updateSemaphore->give(); } else { CSPOT_LOG(error, "Failed to get audio key"); - state = State::FAILED; - loadedSemaphore->give(); + retries++; + state = State::KEY_REQUIRED; + if (retries > 10) { + if (audioFormat > AudioFormat_OGG_VORBIS_96) { + audioFormat = (AudioFormat)(audioFormat - 1); + state = State::QUEUED; + } else { + state = State::FAILED; + playableSemaphore->give(); + } + } } - updateSemaphore->give(); }); state = State::PENDING_KEY; @@ -282,9 +297,8 @@ void QueuedTrack::stepLoadCDNUrl(const std::string& accessKey) { std::string requestUrl = string_format( "https://api.spotify.com/v1/storage-resolve/files/audio/interactive/" - "%s?alt=json&product=9", + "%s?alt=json", bytesToHexString(fileId).c_str()); - auto req = bell::HTTPClient::get( requestUrl, {bell::HTTPClient::ValueHeader( {"Authorization", "Bearer " + accessKey})}); @@ -302,47 +316,39 @@ void QueuedTrack::stepLoadCDNUrl(const std::string& accessKey) { cdnUrl = jsonResult["cdnurl"][0]; #endif - CSPOT_LOG(info, "Received CDN URL, %s", cdnUrl.c_str()); + // CSPOT_LOG(info, "Received CDN URL, %s", cdnUrl.c_str()); state = State::READY; - loadedSemaphore->give(); } catch (...) { CSPOT_LOG(error, "Cannot fetch CDN URL"); state = State::FAILED; - loadedSemaphore->give(); - } -} - -void QueuedTrack::expire() { - if (state != State::QUEUED) { - state = State::FAILED; - loadedSemaphore->give(); } + playableSemaphore->give(); } void QueuedTrack::stepLoadMetadata( Track* pbTrack, Episode* pbEpisode, std::mutex& trackListMutex, std::shared_ptr updateSemaphore) { - // Prepare request ID - std::string requestUrl = string_format( - "hm://metadata/3/%s/%s", - ref.type == TrackReference::Type::TRACK ? "track" : "episode", - bytesToHexString(ref.gid).c_str()); + std::string requestUrl = + string_format("hm://metadata/3/%s/%s", + gid.first == SpotifyFileType::TRACK ? "track" : "episode", + bytesToHexString(gid.second).c_str()); auto responseHandler = [this, pbTrack, pbEpisode, &trackListMutex, - updateSemaphore](MercurySession::Response& res) { + updateSemaphore](MercurySession::Response res) { std::scoped_lock lock(trackListMutex); if (res.parts.size() == 0) { + CSPOT_LOG(info, "Invalid Metadata"); // Invalid metadata, cannot proceed state = State::FAILED; updateSemaphore->give(); - loadedSemaphore->give(); + playableSemaphore->give(); return; } // Parse the metadata - if (ref.type == TrackReference::Type::TRACK) { + if (gid.first == SpotifyFileType::TRACK) { pb_release(Track_fields, pbTrack); pbDecode(*pbTrack, Track_fields, res.parts[0]); } else { @@ -356,29 +362,20 @@ void QueuedTrack::stepLoadMetadata( updateSemaphore->give(); }; // Execute the request - pendingMercuryRequest = ctx->session->execute( - MercurySession::RequestType::GET, requestUrl, responseHandler); + if (pbTrack != NULL || pbEpisode != NULL) + pendingMercuryRequest = ctx->session->execute( + MercurySession::RequestType::GET, requestUrl, responseHandler); // Set the state to pending state = State::PENDING_META; } -TrackQueue::TrackQueue(std::shared_ptr ctx, - std::shared_ptr state) - : bell::Task("CSpotTrackQueue", 1024 * 32, 2, 1), - playbackState(state), - ctx(ctx) { +TrackQueue::TrackQueue(std::shared_ptr ctx) + : bell::Task("CSpotTrackQueue", 1024 * 48, 2, 1), ctx(ctx) { accessKeyFetcher = std::make_shared(ctx); processSemaphore = std::make_shared(); playableSemaphore = std::make_shared(); - // Assign encode callback to track list - playbackState->innerFrame.state.track.funcs.encode = - &TrackReference::pbEncodeTrackList; - playbackState->innerFrame.state.track.arg = ¤tTracks; - pbTrack = Track_init_zero; - pbEpisode = Episode_init_zero; - // Start the task startTask(); }; @@ -387,17 +384,6 @@ TrackQueue::~TrackQueue() { stopTask(); std::scoped_lock lock(tracksMutex); - - pb_release(Track_fields, &pbTrack); - pb_release(Episode_fields, &pbEpisode); -} - -TrackInfo TrackQueue::getTrackInfo(std::string_view identifier) { - for (auto& track : preloadedTracks) { - if (track->identifier == identifier) - return track->trackInfo; - } - return TrackInfo{}; } void TrackQueue::runTask() { @@ -408,17 +394,14 @@ void TrackQueue::runTask() { std::deque> trackQueue; while (isRunning) { - processSemaphore->twait(100); + if (processSemaphore->twait(200)) { + if (!preloadedTracks.size()) + continue; + } // Make sure we have the newest access key accessKey = accessKeyFetcher->getAccessKey(); - - int loadedIndex = currentTracksIndex; - - // No tracks loaded yet - if (loadedIndex < 0) { - continue; - } else { + { std::scoped_lock lock(tracksMutex); trackQueue = preloadedTracks; @@ -426,7 +409,8 @@ void TrackQueue::runTask() { for (auto& track : trackQueue) { if (track) { - this->processTrack(track); + if (this->processTrack(track)) + break; } } } @@ -444,24 +428,11 @@ std::shared_ptr TrackQueue::consumeTrack( std::shared_ptr prevTrack, int& offset) { std::scoped_lock lock(tracksMutex); - if (currentTracksIndex == -1 || currentTracksIndex >= currentTracks.size()) { + if (!preloadedTracks.size()) { + offset = -1; return nullptr; } - // No previous track, return head - if (prevTrack == nullptr) { - offset = 0; - - return preloadedTracks[0]; - } - - // if (currentTracksIndex + preloadedTracks.size() >= currentTracks.size()) { - // offset = -1; - - // // Last track in queue - // return nullptr; - // } - auto prevTrackIter = std::find(preloadedTracks.begin(), preloadedTracks.end(), prevTrack); @@ -471,20 +442,17 @@ std::shared_ptr TrackQueue::consumeTrack( } else { offset = 0; } - if (offset >= preloadedTracks.size()) { // Last track in preloaded queue return nullptr; } - - // Return the current track return preloadedTracks[offset]; } -void TrackQueue::processTrack(std::shared_ptr track) { +bool TrackQueue::processTrack(std::shared_ptr track) { switch (track->state) { case QueuedTrack::State::QUEUED: - track->stepLoadMetadata(&pbTrack, &pbEpisode, tracksMutex, + track->stepLoadMetadata(&track->pbTrack, &track->pbEpisode, tracksMutex, processSemaphore); break; case QueuedTrack::State::KEY_REQUIRED: @@ -492,145 +460,10 @@ void TrackQueue::processTrack(std::shared_ptr track) { break; case QueuedTrack::State::CDN_REQUIRED: track->stepLoadCDNUrl(accessKey); - - if (track->state == QueuedTrack::State::READY) { - if (preloadedTracks.size() < MAX_TRACKS_PRELOAD) { - // Queue a new track to preload - queueNextTrack(preloadedTracks.size()); - } - } - break; default: + return false; // Do not perform any action break; } -} - -bool TrackQueue::queueNextTrack(int offset, uint32_t positionMs) { - const int requestedRefIndex = offset + currentTracksIndex; - - if (requestedRefIndex < 0 || requestedRefIndex >= currentTracks.size()) { - return false; - } - - // in case we re-queue current track, make sure position is updated (0) - if (offset == 0 && preloadedTracks.size() && - preloadedTracks[0]->ref == currentTracks[currentTracksIndex]) { - preloadedTracks.pop_front(); - } - - if (offset <= 0) { - preloadedTracks.push_front(std::make_shared( - currentTracks[requestedRefIndex], ctx, positionMs)); - } else { - preloadedTracks.push_back(std::make_shared( - currentTracks[requestedRefIndex], ctx, positionMs)); - } - return true; } - -bool TrackQueue::skipTrack(SkipDirection dir, bool expectNotify) { - bool skipped = true; - std::scoped_lock lock(tracksMutex); - - if (dir == SkipDirection::PREV) { - uint64_t position = - !playbackState->innerFrame.state.has_position_ms - ? 0 - : playbackState->innerFrame.state.position_ms + - ctx->timeProvider->getSyncedTimestamp() - - playbackState->innerFrame.state.position_measured_at; - - if (currentTracksIndex > 0 && position < 3000) { - queueNextTrack(-1); - - if (preloadedTracks.size() > MAX_TRACKS_PRELOAD) { - preloadedTracks.pop_back(); - } - - currentTracksIndex--; - } else { - queueNextTrack(0); - } - } else { - if (currentTracks.size() > currentTracksIndex + 1) { - preloadedTracks.pop_front(); - - if (!queueNextTrack(preloadedTracks.size() + 1)) { - CSPOT_LOG(info, "Failed to queue next track"); - } - - currentTracksIndex++; - } else { - skipped = false; - } - } - - if (skipped) { - // Update frame data - playbackState->innerFrame.state.playing_track_index = currentTracksIndex; - - if (expectNotify) { - // Reset position to zero - notifyPending = true; - } - } - - return skipped; -} - -bool TrackQueue::hasTracks() { - std::scoped_lock lock(tracksMutex); - - return currentTracks.size() > 0; -} - -bool TrackQueue::isFinished() { - std::scoped_lock lock(tracksMutex); - return currentTracksIndex >= currentTracks.size() - 1; -} - -bool TrackQueue::updateTracks(uint32_t requestedPosition, bool initial) { - std::scoped_lock lock(tracksMutex); - bool cleared = true; - - // Copy requested track list - currentTracks = playbackState->remoteTracks; - currentTracksIndex = playbackState->innerFrame.state.playing_track_index; - - if (initial) { - // Clear preloaded tracks - preloadedTracks.clear(); - - if (currentTracksIndex < currentTracks.size()) { - // Push a song on the preloaded queue - queueNextTrack(0, requestedPosition); - } - - // We already updated track meta, mark it - notifyPending = true; - - playableSemaphore->give(); - } else if (preloadedTracks[0]->loading) { - // try to not re-load track if we are still loading it - - // remove everything except first track - preloadedTracks.erase(preloadedTracks.begin() + 1, preloadedTracks.end()); - - // Push a song on the preloaded queue - CSPOT_LOG(info, "Keeping current track %d", currentTracksIndex); - queueNextTrack(1); - - cleared = false; - } else { - // Clear preloaded tracks - preloadedTracks.clear(); - - // Push a song on the preloaded queue - CSPOT_LOG(info, "Re-loading current track"); - queueNextTrack(0, requestedPosition); - } - - return cleared; -} diff --git a/cspot/src/TrackReference.cpp b/cspot/src/TrackReference.cpp index 3b3b7031..31edfccd 100644 --- a/cspot/src/TrackReference.cpp +++ b/cspot/src/TrackReference.cpp @@ -1,152 +1,53 @@ #include "TrackReference.h" #include "NanoPBExtensions.h" -#include "Utils.h" -#include "protobuf/spirc.pb.h" +#include "protobuf/connect.pb.h" using namespace cspot; -static constexpr auto base62Alphabet = - "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +static std::string empty_string = ""; TrackReference::TrackReference() : type(Type::TRACK) {} -void TrackReference::decodeURI() { - if (gid.size() == 0) { - // Episode GID is being fetched via base62 encoded URI - auto idString = uri.substr(uri.find_last_of(":") + 1, uri.size()); - gid = {0}; - - std::string_view alphabet(base62Alphabet); - for (int x = 0; x < idString.size(); x++) { - size_t d = alphabet.find(idString[x]); - gid = bigNumMultiply(gid, 62); - gid = bigNumAdd(gid, d); - } - - if (uri.find("episode:") != std::string::npos) { - type = Type::EPISODE; - } - } -} - bool TrackReference::operator==(const TrackReference& other) const { return other.gid == gid && other.uri == uri; } -bool TrackReference::pbEncodeTrackList(pb_ostream_t* stream, - const pb_field_t* field, - void* const* arg) { - auto trackQueue = *static_cast*>(*arg); - static TrackRef msg = TrackRef_init_zero; - - // Prepare nanopb callbacks - msg.context.funcs.encode = &bell::nanopb::encodeString; - msg.uri.funcs.encode = &bell::nanopb::encodeString; - msg.gid.funcs.encode = &bell::nanopb::encodeVector; - msg.queued.funcs.encode = &bell::nanopb::encodeBoolean; - - for (auto trackRef : trackQueue) { +bool TrackReference::pbEncodeProvidedTracks(pb_ostream_t* stream, + const pb_field_t* field, + void* const* arg) { + auto trackPacket = (std::pair*>*)(*arg); + if (*trackPacket->first >= trackPacket->second->size() || + !trackPacket->second->size()) + return true; + for (int i = *trackPacket->first; i < trackPacket->second->size(); i++) { if (!pb_encode_tag_for_field(stream, field)) { return false; } - - msg.gid.arg = &trackRef.gid; - msg.uri.arg = &trackRef.uri; - msg.context.arg = &trackRef.context; - msg.queued.arg = &trackRef.queued; - - if (!pb_encode_submessage(stream, TrackRef_fields, &msg)) { + if (!pb_encode_submessage(stream, ProvidedTrack_fields, + &(trackPacket->second->at(i)))) return false; - } + //if there's a delimiter, or the tracks are over the track treshhold + if (trackPacket->second->at(i).removed != NULL || + i - *trackPacket->first >= TRACK_SEND_LIMIT) + return true; } - return true; } -bool TrackReference::pbDecodeTrackList(pb_istream_t* stream, - const pb_field_t* field, void** arg) { - auto trackQueue = static_cast*>(*arg); +bool TrackReference::pbDecodeProvidedTracks(pb_istream_t* stream, + const pb_field_t* field, + void** arg) { + auto trackQueue = static_cast*>(*arg); // Push a new reference - trackQueue->push_back(TrackReference()); + trackQueue->push_back(ProvidedTrack()); auto& track = trackQueue->back(); - bool eof = false; - pb_wire_type_t wire_type; - pb_istream_t substream; - uint32_t tag; - - while (!eof) { - if (!pb_decode_tag(stream, &wire_type, &tag, &eof)) { - // Decoding failed and not eof - if (!eof) { - return false; - } - // EOF - } else { - switch (tag) { - case TrackRef_uri_tag: - case TrackRef_context_tag: - case TrackRef_gid_tag: { - // Make substream - if (!pb_make_string_substream(stream, &substream)) { - - return false; - } - - uint8_t* destBuffer = nullptr; - - // Handle GID - if (tag == TrackRef_gid_tag) { - track.gid.resize(substream.bytes_left); - destBuffer = &track.gid[0]; - } else if (tag == TrackRef_context_tag) { - track.context.resize(substream.bytes_left); - - destBuffer = reinterpret_cast(&track.context[0]); - } else if (tag == TrackRef_uri_tag) { - track.uri.resize(substream.bytes_left); - - destBuffer = reinterpret_cast(&track.uri[0]); - } - - if (!pb_read(&substream, destBuffer, substream.bytes_left)) { - return false; - } - - // Close substream - if (!pb_close_string_substream(stream, &substream)) { - return false; - } - - break; - } - case TrackRef_queued_tag: { - uint32_t queuedValue; - - // Decode boolean - if (!pb_decode_varint32(stream, &queuedValue)) { - return false; - } - - // Cast down to bool - track.queued = (bool)queuedValue; - - break; - } - default: - // Field not known, skip - pb_skip_field(stream, wire_type); - - break; - } - } - } - - // Fill in GID when only URI is provided - track.decodeURI(); + if (!pb_decode(stream, ProvidedTrack_fields, &track)) + return false; + track.full_metadata_count = track.metadata_count; return true; -} +} \ No newline at end of file diff --git a/cspot/src/Utils.cpp b/cspot/src/Utils.cpp index fa5a3d95..dfdd588e 100644 --- a/cspot/src/Utils.cpp +++ b/cspot/src/Utils.cpp @@ -11,6 +11,11 @@ #include #endif +static std::string Base62Alphabet = + "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +static char Base64Alphabet[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + unsigned long long getCurrentTimestamp() { return std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()) @@ -28,6 +33,34 @@ uint64_t hton64(uint64_t value) { } } +std::string base64Encode(const std::vector& v) { + std::string ss; + int nLenOut = 0; + int index = 0; + while (index < v.size()) { + size_t decode_size = v.size() - index; + unsigned long n = v[index]; + n <<= 8; + n |= (decode_size > 1) ? v[index + 1] : 0; + n <<= 8; + n |= (decode_size > 2) ? v[index + 2] : 0; + uint8_t m4 = n & 0x3f; + n >>= 6; + uint8_t m3 = n & 0x3f; + n >>= 6; + uint8_t m2 = n & 0x3f; + n >>= 6; + uint8_t m1 = n & 0x3f; + + ss.push_back(Base64Alphabet[m1]); + ss.push_back(Base64Alphabet[m2]); + ss.push_back(decode_size > 1 ? Base64Alphabet[m3] : '='); + ss.push_back(decode_size > 2 ? Base64Alphabet[m4] : '='); + index += 3; + } + return ss; +} + std::vector stringHexToBytes(const std::string& s) { std::vector v; v.reserve(s.length() / 2); @@ -151,4 +184,26 @@ std::string urlDecode(std::string str) { } return encodedString; +} + +std::pair> base62Decode(std::string uri) { + std::vector n = std::vector({0}); + SpotifyFileType type = SpotifyFileType::UNKNOWN; + auto it = uri.begin(); + if (uri.find(":") != std::string::npos) { + if (uri.find("episode:") != std::string::npos) { + type = SpotifyFileType::EPISODE; + } else if (uri.find("track:") != std::string::npos) { + type = SpotifyFileType::TRACK; + } + it += uri.rfind(":") + 1; + } + while (it != uri.end()) { + size_t d = Base62Alphabet.find(*it); + n = bigNumMultiply(n, 62); + n = bigNumAdd(n, d); + it++; + } + + return std::make_pair(type, n); } \ No newline at end of file diff --git a/flake.nix b/flake.nix index 9c07fb73..59955e12 100644 --- a/flake.nix +++ b/flake.nix @@ -30,15 +30,7 @@ clang-tools = pkgs.clang-tools.override {llvmPackages = llvm;}; - apps = { - }; - - packages = { - target-cli = llvm.stdenv.mkDerivation { - name = "cspotcli"; - src = ./.; - cmakeFlags = ["-DCSPOT_TARGET_CLI=ON"]; - nativeBuildInputs = with pkgs; [ + cspot-pkgs = with pkgs; [ avahi avahi-compat cmake @@ -50,6 +42,16 @@ portaudio protobuf ]; + + apps = { + }; + + packages = { + target-cli = llvm.stdenv.mkDerivation { + name = "cspotcli"; + src = ./.; + cmakeFlags = ["-DCSPOT_TARGET_CLI=ON"]; + nativeBuildInputs = cspot-pkgs; # Patch nanopb shebangs to refer to provided python postPatch = '' patchShebangs cspot/bell/external/nanopb/generator/* @@ -60,7 +62,7 @@ devShells = { default = pkgs.mkShell { - packages = with pkgs; [cmake unstable.mbedtls ninja python3] ++ [clang-tools llvm.clang]; + packages = cspot-pkgs; }; }; in { diff --git a/targets/cli/CliPlayer.cpp b/targets/cli/CliPlayer.cpp index 1642c4ec..75761eec 100644 --- a/targets/cli/CliPlayer.cpp +++ b/targets/cli/CliPlayer.cpp @@ -14,13 +14,13 @@ #include "BellDSP.h" // for BellDSP, BellDSP::FadeEffect, BellDS... #include "BellUtils.h" // for BELL_SLEEP_MS #include "CentralAudioBuffer.h" // for CentralAudioBuffer::AudioChunk, Cent... +#include "DeviceStateHandler.h" // for DeviceStateHandler, DeviceStateHandler::CommandType #include "Logger.h" -#include "SpircHandler.h" // for SpircHandler, SpircHandler::EventType -#include "StreamInfo.h" // for BitWidth, BitWidth::BW_16 -#include "TrackPlayer.h" // for TrackPlayer +#include "StreamInfo.h" // for BitWidth, BitWidth::BW_16 +#include "TrackPlayer.h" // for TrackPlayer CliPlayer::CliPlayer(std::unique_ptr sink, - std::shared_ptr handler) + std::shared_ptr handler) : bell::Task("player", 1024, 0, 0) { this->handler = handler; this->audioSink = std::move(sink); @@ -32,54 +32,67 @@ CliPlayer::CliPlayer(std::unique_ptr sink, this->dsp = std::make_shared(this->centralAudioBuffer); #endif - auto hashFunc = std::hash(); - - this->handler->getTrackPlayer()->setDataCallback( - [this, &hashFunc](uint8_t* data, size_t bytes, std::string_view trackId) { - auto hash = hashFunc(trackId); - - return this->centralAudioBuffer->writePCM(data, bytes, hash); + this->handler->trackPlayer->setDataCallback( + [this](uint8_t* data, size_t bytes, size_t trackId, + bool STORAGE_VOLATILE) { + return this->centralAudioBuffer->writePCM(data, bytes, trackId); }); this->isPaused = false; - this->handler->setEventHandler( - [this](std::unique_ptr event) { - switch (event->eventType) { - case cspot::SpircHandler::EventType::PLAY_PAUSE: - if (std::get(event->data)) { - this->pauseRequested = true; - } else { - this->isPaused = false; - this->pauseRequested = false; - } + this->handler->stateCallback = + [this](cspot::DeviceStateHandler::Command event) { + switch (event.commandType) { + case cspot::DeviceStateHandler::CommandType::PAUSE: + this->pauseRequested = true; break; - case cspot::SpircHandler::EventType::FLUSH: { + case cspot::DeviceStateHandler::CommandType::PLAY: + this->isPaused = false; + this->pauseRequested = false; + break; + case cspot::DeviceStateHandler::CommandType::FLUSH: { this->centralAudioBuffer->clearBuffer(); break; } - case cspot::SpircHandler::EventType::DISC: + case cspot::DeviceStateHandler::CommandType::DISC: + this->centralAudioBuffer->clearBuffer(); + tracks.at(0)->trackMetrics->endTrack(); + this->handler->ctx->playbackMetrics->sendEvent(tracks[0]); + tracks.clear(); + this->playlistEnd = true; + break; + case cspot::DeviceStateHandler::CommandType::SEEK: this->centralAudioBuffer->clearBuffer(); break; - case cspot::SpircHandler::EventType::SEEK: + case cspot::DeviceStateHandler::CommandType::SKIP_NEXT: + case cspot::DeviceStateHandler::CommandType::SKIP_PREV: this->centralAudioBuffer->clearBuffer(); break; - case cspot::SpircHandler::EventType::PLAYBACK_START: - this->isPaused = true; - this->playlistEnd = false; + case cspot::DeviceStateHandler::CommandType::PLAYBACK_START: this->centralAudioBuffer->clearBuffer(); + if (tracks.size()) + tracks.clear(); + this->isPaused = false; + this->playlistEnd = false; break; - case cspot::SpircHandler::EventType::DEPLETED: + case cspot::DeviceStateHandler::CommandType::PLAYBACK: + tracks.push_back( + std::get>(event.data)); + this->isPaused = false; + this->playlistEnd = false; + break; + case cspot::DeviceStateHandler::CommandType::DEPLETED: + this->centralAudioBuffer->clearBuffer(); this->playlistEnd = true; break; - case cspot::SpircHandler::EventType::VOLUME: { - int volume = std::get(event->data); + case cspot::DeviceStateHandler::CommandType::VOLUME: { + int volume = std::get(event.data); break; } default: break; } - }); + }; startTask(); } @@ -111,17 +124,29 @@ void CliPlayer::runTask() { if (!chunk || chunk->pcmSize == 0) { if (this->playlistEnd) { - this->handler->notifyAudioEnded(); - this->playlistEnd = false; + this->playlistEnd = false; + if (tracks.size()) { + tracks.at(0)->trackMetrics->endTrack(); + this->handler->ctx->playbackMetrics->sendEvent(tracks[0]); + tracks.clear(); + this->handler->putPlayerState(); + } + lastHash = 0; } BELL_SLEEP_MS(10); continue; } else { if (lastHash != chunk->trackHash) { - std::cout << " Last hash " << lastHash << " new hash " - << chunk->trackHash << std::endl; + if (lastHash) { + tracks.at(0)->trackMetrics->endTrack(); + this->handler->ctx->playbackMetrics->sendEvent(tracks[0]); + tracks.pop_front(); + this->handler->trackPlayer->onTrackEnd(true); + } lastHash = chunk->trackHash; - this->handler->notifyAudioReachedPlayback(); + tracks.at(0)->trackMetrics->startTrackPlaying( + tracks.at(0)->requestedPosition); + this->handler->putPlayerState(); } #ifndef BELL_DISABLE_CODECS diff --git a/targets/cli/CliPlayer.h b/targets/cli/CliPlayer.h index 0857a640..65b7f122 100644 --- a/targets/cli/CliPlayer.h +++ b/targets/cli/CliPlayer.h @@ -7,29 +7,31 @@ #include // for mutex #include // for string -#include "AudioSink.h" // for AudioSink -#include "BellTask.h" // for Task +#include "AudioSink.h" // for AudioSink +#include "BellTask.h" // for Task +#include "DeviceStateHandler.h" // for DeviceStateHandler namespace bell { class BellDSP; class CentralAudioBuffer; } // namespace bell namespace cspot { -class SpircHandler; +class DeviceStateHandler; } // namespace cspot class CliPlayer : public bell::Task { public: CliPlayer(std::unique_ptr sink, - std::shared_ptr spircHandler); + std::shared_ptr handler); void disconnect(); private: std::string currentTrackId; - std::shared_ptr handler; + std::shared_ptr handler; std::shared_ptr dsp; std::unique_ptr audioSink; std::shared_ptr centralAudioBuffer; + std::deque> tracks = {}; void feedData(uint8_t* data, size_t len); diff --git a/targets/cli/main.cpp b/targets/cli/main.cpp index a4249875..58fe9f7d 100644 --- a/targets/cli/main.cpp +++ b/targets/cli/main.cpp @@ -1,18 +1,18 @@ -#include // for __base, function +#include +#include // for __base, function +#include #include // for operator!=, map, map<>::mapped_type +#include // for std::osstringstream #include // for invalid_argument #include // for remove_extent_t #include // for vector -#include -#include -#include // for std::osstringstream #include "BellHTTPServer.h" // for BellHTTPServer #include "BellLogger.h" // for setDefaultLogger, AbstractLogger #include "CSpotContext.h" // for Context, Context::ConfigState #include "CliPlayer.h" // for CliPlayer +#include "DeviceStateHandler.h" // for DeviceStateHandler #include "MDNSService.h" // for MDNSService -#include "SpircHandler.h" // for SpircHandler #include "WrappedSemaphore.h" // for WrappedSemaphore #include "civetweb.h" // for mg_header, mg_get_request_info #include "nlohmann/json.hpp" // for basic_json<>::object_t, basic_json @@ -135,99 +135,109 @@ int main(int argc, char** argv) { isRunning = false; }; - try { - auto args = CommandLineArguments::parse(argc, argv); - if (args->shouldShowHelp) { - std::cout << "Usage: cspotcli [OPTION]...\n"; - std::cout << "Emulate a Spotify connect speaker.\n"; - std::cout << "\n"; - std::cout << "Run without any arguments to authenticate by using mDNS on " - "the local network (open the spotify app and CSpot should " - "appear as a device on the local network). \n"; - std::cout << "Alternatively you can specify a username and password to " - "login with."; - std::cout << "\n"; - std::cout << "-u, --username your spotify username\n"; - std::cout << "-p, --password your spotify password, note that " - "if you use facebook login you can set a password in your " - "account settings\n"; - std::cout << "-c, --credentials json file to store/load reusable credentials\n"; - std::cout << "-b, --bitrate bitrate (320, 160, 96)\n"; - std::cout << "\n"; - std::cout << "ddd 2022\n"; - return 0; - } + while (true) { + try { + auto args = CommandLineArguments::parse(argc, argv); + if (args->shouldShowHelp) { + std::cout << "Usage: cspotcli [OPTION]...\n"; + std::cout << "Emulate a Spotify connect speaker.\n"; + std::cout << "\n"; + std::cout + << "Run without any arguments to authenticate by using mDNS on " + "the local network (open the spotify app and CSpot should " + "appear as a device on the local network). \n"; + std::cout << "Alternatively you can specify a username and password to " + "login with."; + std::cout << "\n"; + std::cout << "-u, --username your spotify username\n"; + std::cout + << "-p, --password your spotify password, note that " + "if you use facebook login you can set a password in your " + "account settings\n"; + std::cout + << "-c, --credentials json file to store/load reusable " + "credentials\n"; + std::cout << "-b, --bitrate bitrate (320, 160, 96)\n"; + std::cout << "\n"; + std::cout << "ddd 2022\n"; + return 0; + } - // Create a login blob, pass a device name - auto loginBlob = std::make_shared("CSpot player"); + // Create a login blob, pass a device name + auto loginBlob = std::make_shared("CSpot player"); - // Login using Command line arguments - if (!args->username.empty()) { - loginBlob->loadUserPass(args->username, args->password); - loggedInSemaphore->give(); - } - // reusable credentials - else if (!args->credentials.empty()) { + // Login using Command line arguments + if (!args->username.empty()) { + loginBlob->loadUserPass(args->username, args->password); + loggedInSemaphore->give(); + } + // reusable credentials + else if (!args->credentials.empty()) { std::ifstream file(args->credentials); std::ostringstream credentials; credentials << file.rdbuf(); loginBlob->loadJson(credentials.str()); loggedInSemaphore->give(); - } - // ZeroconfAuthenticator - else { - zeroconfServer->blob = loginBlob; - zeroconfServer->onAuthSuccess = [loggedInSemaphore]() { - loggedInSemaphore->give(); - }; - zeroconfServer->registerHandlers(); - } - - // Wait for authentication to complete - loggedInSemaphore->wait(); - auto ctx = cspot::Context::createFromBlob(loginBlob); - - // Apply preferences - if (args->setBitrate) { - ctx->config.audioFormat = args->bitrate; - } - - CSPOT_LOG(info, "Creating player"); - ctx->session->connectWithRandomAp(); - ctx->config.authData = ctx->session->authenticate(loginBlob); - - // Auth successful - if (ctx->config.authData.size() > 0) { - // when credentials file is set, then store reusable credentials - if (!args->credentials.empty()) { - std::ofstream file(args->credentials); - file << ctx->getCredentialsJson(); } - - // Start spirc task - auto handler = std::make_shared(ctx); - - // Start handling mercury messages - ctx->session->startTask(); - - // Create a player, pass the handler - auto player = std::make_shared(std::move(audioSink), handler); - - // If we wanted to handle multiple devices, we would halt this loop - // when a new zeroconf login is requested, and reinitialize the session - while (isRunning) { - ctx->session->handlePacket(); + // ZeroconfAuthenticator + else { + zeroconfServer->blob = loginBlob; + zeroconfServer->onAuthSuccess = [loggedInSemaphore]() { + loggedInSemaphore->give(); + }; + zeroconfServer->registerHandlers(); } + while (true) { + // Wait for authentication to complete + loggedInSemaphore->wait(); + isRunning = true; + auto ctx = cspot::Context::createFromBlob(loginBlob); + + // Apply preferences + if (args->setBitrate) { + ctx->config.audioFormat = args->bitrate; + } - // Never happens, but required for above case - handler->disconnect(); - player->disconnect(); + CSPOT_LOG(info, "Creating player"); + ctx->session->connectWithRandomAp(); + ctx->config.authData = ctx->session->authenticate(loginBlob); + + // Auth successful + if (ctx->config.authData.size() > 0) { + // when credentials file is set, then store reusable credentials + if (!args->credentials.empty()) { + std::ofstream file(args->credentials); + file << ctx->getCredentialsJson(); + } + + // Start DeviceStateHandler + auto handler = std::make_shared( + ctx, zeroconfServer->onClose); + + // Start handling mercury messages + ctx->session->startTask(); + + // Create a player, pass the handler + auto player = + std::make_shared(std::move(audioSink), handler); + + // If we wanted to handle multiple devices, we would halt this loop + // when a new zeroconf login is requested, and reinitialize the session + while (isRunning) { + ctx->session->handlePacket(); + } + + // Never happens, but required for above case + handler->disconnect(); + player->disconnect(); + } + } + } catch (std::invalid_argument e) { + std::cout << "Invalid options passed: " << e.what() << "\n"; + std::cout << "Pass --help for more informaton. \n"; + continue; + //return 1; // we exit with an non-zero exit code } - - } catch (std::invalid_argument e) { - std::cout << "Invalid options passed: " << e.what() << "\n"; - std::cout << "Pass --help for more informaton. \n"; - return 1; // we exit with an non-zero exit code } return 0; diff --git a/targets/esp32/CMakeLists.txt b/targets/esp32/CMakeLists.txt index fe3cb34f..2254e6e9 100644 --- a/targets/esp32/CMakeLists.txt +++ b/targets/esp32/CMakeLists.txt @@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.5) # Don't override EXTRA_COMPONENT_DIRS as platformio uses it. Instead we append # see https://github.com/platformio/platform-espressif32/issues/341 list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) -list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/led_strip) +#list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/led_strip) if(NOT IDF_NO_INCLUDE) include($ENV{IDF_PATH}/tools/cmake/project.cmake) diff --git a/targets/esp32/components/VS1053/CMakeLists.txt b/targets/esp32/components/VS1053/CMakeLists.txt new file mode 100644 index 00000000..e26e4236 --- /dev/null +++ b/targets/esp32/components/VS1053/CMakeLists.txt @@ -0,0 +1,9 @@ +set(CMAKE_CXX_STANDARD 17) + idf_component_register( SRCS "src/VS1053.cpp" + "../../../../cspot/bell/main/utilities/BellLogger.cpp" + "../../../../cspot/bell/main/platform/esp/WrappedSemaphore.cpp" + INCLUDE_DIRS + "include" + "../../../../cspot/bell/main/utilities/include" + "../../../../cspot/bell/main/platform/" + PRIV_REQUIRES fatfs) diff --git a/targets/esp32/components/VS1053/Kconfig b/targets/esp32/components/VS1053/Kconfig new file mode 100644 index 00000000..9b45b46c --- /dev/null +++ b/targets/esp32/components/VS1053/Kconfig @@ -0,0 +1,69 @@ +menu "VS1053 Configuration" + + menu "VS1053 PIN Configuration" + + config GPIO_MISO + int "GPIO pin MISO" + range -1 39 + default 19 + + config GPIO_MOSI + int "GPIO pin MOSI" + range -1 39 + default 23 + + config GPIO_CLK + int "GPIO pin CLK" + range -1 39 + default 18 + + config GPIO_VS_CS + int "GPIO pin VS CS" + range -1 39 + default 4 + + config GPIO_VS_DCS + int "GPIO pin VS DCS" + range -1 39 + default 21 + + config GPIO_VS_RESET + int "GPIO pin VS RESET" + range -1 39 + default 0 + + config GPIO_VS_DREQ + int "GPIO pin VS DREQ" + range -1 39 + default 22 + + config GPIO_SD_CS + int "GPIO pin SD CS" + range -1 39 + default 5 + endmenu + +choice VS_PLUGIN + prompt "VS1053 plugin" + default VS_FLAC + help + you have to choose between special audio compability or a spectrum analyzer + config VS_DSD64 + bool "with dsd patch" + config VS_FLAC + bool "with flac patch" + config VS_FLAC_LATM + bool "with flac & latm/loas patch" + config VS_LATM + bool "with latm/loas patch" + config VS_PITCH + bool "with pitch plugin" + config VS_SPECTRUM_ANALYZER + bool "with spectrum analyzer plugin" +endchoice + + +config REPORT_ON_SCREEN + bool "REPORT_ON_SCREEN" + +endmenu diff --git a/targets/esp32/components/VS1053/component.mk b/targets/esp32/components/VS1053/component.mk new file mode 100644 index 00000000..e69de29b diff --git a/targets/esp32/components/VS1053/include/VS1053.h b/targets/esp32/components/VS1053/include/VS1053.h new file mode 100644 index 00000000..6326a186 --- /dev/null +++ b/targets/esp32/components/VS1053/include/VS1053.h @@ -0,0 +1,243 @@ +#ifndef VS1053_H +#define VS1053_H + +#include +#include //for memset +#include //for dequeue +#include //for function +#include +#include + +#include "esp_err.h" + +#include +#include + +#include "freertos/semphr.h" +#include "freertos/stream_buffer.h" +#include "freertos/task.h" + +#include "vs10xx_uc.h" +#ifdef CONFIG_VS_DSD64 +#include "patches_dsd.h" +#endif +#ifdef CONFIG_VS_FLAC +#include "patches_flac.h" +#endif +#ifdef CONFIG_VS_FLAC_LATM +#include "patches_flac_latm.h" +#endif +#ifdef CONFIG_VS_LATM +#include "patches_latm.h" +#endif +#ifdef CONFIG_VS_PITCH +#include "patches_pitch.h" +#endif +#ifdef CONFIG_VS_SPECTRUM_ANALYZER +#include "spectrum_analyzer.h" +#endif + +#define VERSION 1 +#define VS1053_CHUNK_SIZE 16 // chunck size +#define VS1053_PACKET_SIZE 32 +#define BUF_SIZE_CMD 1028 +#define BUF_SIZE_FEED 4096 * 4 + +#define SDI_END_FILL_BYTES_FLAC 12288 +#define SDI_END_FILL_BYTES 2050 + +#define REPORT_INTERVAL 4096 +#define REPORT_INTERVAL_MIDI 512 +/** + * + * callback for the command_pipeline + * + */ +class VS1053_SINK; +class VS1053_TRACK { + public: + VS1053_TRACK(size_t track_id = 0, size_t buffer_size = BUF_SIZE_FEED); + ~VS1053_TRACK(); + /** + * feed data to dataBuffer + * @param data pointer to byte array + * @param len length of the byte array + * @warning always call data_request, before feeding data, + * to get available space in dataBuffer + */ + size_t feed_data(uint8_t* data, size_t len, bool STORAGE_VOLATILE = 0); + void empty_feed(); + void run_track(size_t FILL_BUFFER_BEFORE_PLAYSTART = 0); + enum VS_TRACK_STATE { + tsPlaybackStart = 0, + tsPlayback = 1, + tsPlaybackSeekable = 2, + tsPlaybackPaused = 3, + tsSoftCancel = 4, + tsCancel = 5, + tsCancelAwait = 6, + tsStopped = 7 + } state = tsStopped; + size_t header_size = 0; + size_t track_id; + StaticStreamBuffer_t xStaticStreamBuffer; + StreamBufferHandle_t dataBuffer; + uint8_t* ucBufferStorage; + + private: +}; +class VS1053_SINK { + public: + /** + * `CONSTRUCTOR` + * + * PULLS CS and DCS HIGH. + * If RESET >= 0, VS1053 gets hardreset. + * For sharing the SPI_BUS with a SD-Card, the CS-pins + * of the other devices are needed to be pulled high + * before mounting the SD-card. + * After mounting the SD-card, you can add the other devices + * + * @param RESET GPIO_PIN_NUM, if + */ + VS1053_SINK(); + + /** + * DECONSTRUCTOR + */ + ~VS1053_SINK(); + typedef std::function command_callback; + //typedef std::function command_callback; + /** + * `init feed` + * add the VS 1053 to the SPI_BUS, test the device and + * add vs_loop to freertosTask + * + * @param SPI pointer to the used SPI peripheral + * @param SPI_semaphore semaphore for the SPI_BUS, NULL if uninitiallized + * + * @return `ESP_OK` if setup worked. + * @return `ESP_ERR_INVALID_RESPONSE` if the register response is wrong. + * @return `ESP_ERR_NOT_SUPPORTED` if the chip is not a VS1053. + * @return `ESP_ERR_NOT_FOUND` if the chipNumber is not recognized. + */ + esp_err_t init(spi_host_device_t SPI, + SemaphoreHandle_t* SPI_semaphore = NULL); + /** + * stops data feed imeaditly + */ + void stop_feed(); + /** + * stops data feed if dataBuffer contains no more + */ + void soft_stop_feed(); + /** + * feed data to commandBuffer + * @param command_callback callback function + * + */ + uint8_t feed_command(command_callback commandCallback); + void set_volume_logarithmic(size_t vol); + /** + * set volume through cmd_pipeline, sets left and right volume to vol + * @param vol 0...100, gets capped if bigger + */ + void set_volume(uint8_t vol); + /** + * set volume through cmd_pipeline, sets separate volume for left and right channel + * @param left 0...100, gets capped if bigger + * @param right 0...100, gets capped if bigger + */ + void set_volume(uint8_t left, uint8_t right); + /** + * get available Space in dataBuffer + * @return free space available in dataBuffer + */ + size_t data_request(std::shared_ptr track); + /** + * loads Usercode(PATCH) + * @param plugin uint8_t * to plugin array + * @param sizeofpatch length of the array + */ + void load_user_code(const unsigned short* plugin, uint16_t sizeofpatch); + /** + * test SPI communication and if the board is a VS1053 + * @return `ESP_OK` if setup worked. + * @return `ESP_ERR_INVALID_RESPONSE` if the register response is wrong. + * @return `ESP_ERR_NOT_SUPPORTED` if the chip is not a VS1053. + * @return `ESP_ERR_NOT_FOUND` if the chipNumber is not recognized. + */ + esp_err_t test_comm(const char* header); + + void run_feed(size_t); + + std::function state_callback = nullptr; + enum Audio_Format { + afUnknown, + afRiff, + afOggVorbis, + afMp1, + afMp2, + afMp3, + afAacMp4, + afAacAdts, + afAacAdif, + afFlac, + afWma, + afMidi, + afDsd64, + afLatm + } audioFormat = afUnknown; + + std::deque command_callbacks; + std::deque> tracks; + + void get_audio_format(Audio_Format* audioFormat, size_t* endFillBytes); + void control_mode_on(); + void control_mode_off(); + void data_mode_on(); + void data_mode_off(); + uint16_t read_register(uint8_t _reg); + bool write_register(uint8_t _reg, uint16_t _value); + uint32_t read_mem32(uint16_t addr); + uint32_t read_mem32_counter(uint16_t addr); + uint16_t read_mem(uint16_t addr); + void write_mem(uint16_t addr, uint16_t data); + void write_mem32(uint16_t addr, uint32_t data); + bool sdi_send_buffer(uint8_t* data, size_t len); + void remove_track(std::shared_ptr track) { + for (int i = 0; i < tracks.size(); i++) + if (tracks[i]->track_id == track->track_id) + tracks.erase(tracks.begin() + i); + }; + void start_track(std::shared_ptr, size_t); + size_t track_seekable(size_t); + void cancel_track(VS1053_TRACK::VS_TRACK_STATE* state); + bool is_cancelled(VS1053_TRACK::VS_TRACK_STATE* state, uint8_t, size_t); + size_t get_track_info(size_t, uint8_t&, size_t&); + void new_state(VS1053_TRACK::VS_TRACK_STATE&, VS1053_TRACK::VS_TRACK_STATE); + void new_track(std::shared_ptr track); + + void delete_all_tracks(void); + size_t spaces_available(size_t); + size_t command_pointer = 0, command_reader = 0; + bool isRunning = false; + + private: + spi_device_handle_t SPIHandleLow; + spi_device_handle_t SPIHandleFast; + uint8_t curvol; // Current volume setting 0..100% + int playMode = 0; + uint8_t chipVersion; // Version of hardware + SemaphoreHandle_t* SPI_semaphore = NULL; + TaskHandle_t VS_TASK; + void await_data_request(); + bool is_seekable(VS1053_TRACK::VS_TRACK_STATE* state); + bool sdi_send_fillers(uint8_t, size_t len); + void wram_write(uint16_t address, uint16_t data); + uint16_t wram_read(uint16_t address); + size_t (*data_callback)(uint8_t*, size_t) = NULL; + TaskHandle_t task_handle = NULL; +}; + +#endif \ No newline at end of file diff --git a/targets/esp32/components/VS1053/include/patches_dsd.h b/targets/esp32/components/VS1053/include/patches_dsd.h new file mode 100644 index 00000000..d9ac29d9 --- /dev/null +++ b/targets/esp32/components/VS1053/include/patches_dsd.h @@ -0,0 +1,983 @@ + +#ifndef SKIP_PLUGIN_VARNAME +const unsigned short PLUGIN[] = { + /* Compressed plugin */ +#endif + 0x0007, 0x0001, /*copy 1*/ + 0x8050, 0x0006, 0x001e, /*copy 30*/ + 0x2a00, 0xc000, 0x3e12, 0xb817, 0x3e14, 0xf812, 0x3e01, 0xb811, 0x0007, + 0x9717, 0x0020, 0xffd2, 0x0030, 0x11d1, 0x3111, 0x8024, 0x3704, 0xc024, + 0x3b81, 0x8024, 0x3101, 0x8024, 0x3b81, 0x8024, 0x3f04, 0xc024, 0x2808, + 0x4800, 0x36f1, 0x9811, 0x0007, 0x0001, /*copy 1*/ + 0x8060, 0x0006, 0x053e, /*copy 1342*/ + 0xf400, 0x4095, 0x0000, 0x02c2, 0x6124, 0x0024, 0x0000, 0x0024, 0x2800, + 0x1ac5, 0x4192, 0x4542, 0x0000, 0x0041, 0x2000, 0x0015, 0x0030, 0x0317, + 0x2000, 0x0000, 0x3f00, 0x4024, 0x2000, 0x0000, 0x0000, 0x0000, 0x3e12, + 0x3800, 0x3e00, 0xb804, 0x0030, 0x0015, 0x0007, 0x8257, 0x3700, 0x984c, + 0xf224, 0x1444, 0xf224, 0x0024, 0x0008, 0x0002, 0x2910, 0x0181, 0x0000, + 0x1bc8, 0xb428, 0x1402, 0x0000, 0x8004, 0x2910, 0x0195, 0x0000, 0x1bc8, + 0xb428, 0x0024, 0x0006, 0x0095, 0x2800, 0x2945, 0x3e13, 0x780e, 0x3e11, + 0x7803, 0x3e13, 0xf806, 0x3e11, 0xf801, 0x3510, 0xb808, 0x003f, 0xe004, + 0xfec4, 0x3800, 0x48be, 0x17c3, 0xfec6, 0x41c2, 0x48be, 0x4497, 0x4090, + 0x1c46, 0xf06c, 0x0024, 0x2400, 0x2580, 0x6090, 0x41c3, 0x6628, 0x1c47, + 0x0000, 0x0024, 0x2800, 0x2449, 0xf07e, 0x0024, 0xf400, 0x4182, 0x673a, + 0x1c46, 0x0000, 0x0024, 0x2800, 0x2589, 0xf06c, 0x0024, 0xf400, 0x41c3, + 0x0000, 0x0024, 0x4224, 0x3442, 0x2903, 0xdc80, 0x4336, 0x37c3, 0x0000, + 0x1805, 0x2903, 0xdc80, 0x4508, 0x40c2, 0x450a, 0x9808, 0x0000, 0x0207, + 0xa478, 0x1bc0, 0xc45a, 0x1807, 0x0030, 0x03d5, 0x3d01, 0x5bc1, 0x36f3, + 0xd806, 0x3601, 0x5803, 0x36f3, 0x0024, 0x36f3, 0x580e, 0x0007, 0x8257, + 0x0000, 0x6004, 0x3730, 0x8024, 0xb244, 0x1c04, 0xd428, 0x3c02, 0x0006, + 0xc717, 0x2800, 0x2d05, 0x4284, 0x0024, 0x3613, 0x3c02, 0x0006, 0xc357, + 0x2901, 0x6a00, 0x3e11, 0x5c05, 0x4284, 0x1bc5, 0x0007, 0x8257, 0x2800, + 0x3285, 0x0002, 0x0001, 0x3701, 0x0024, 0x0006, 0xc357, 0xb412, 0x9c02, + 0x002e, 0xe001, 0x2800, 0x3005, 0x6212, 0x0024, 0x0000, 0x0024, 0x2800, + 0x3295, 0x0000, 0x0024, 0x0030, 0x0117, 0x3f00, 0x0024, 0x3613, 0x0024, + 0x3e10, 0x3813, 0x3e14, 0x8024, 0x3e04, 0x8024, 0x2900, 0x4b40, 0x0006, + 0x02d3, 0x36e3, 0x0024, 0x3009, 0x1bd3, 0x0007, 0x8257, 0x3700, 0x8024, + 0xf224, 0x0024, 0x0000, 0x0024, 0x2800, 0x3491, 0x3600, 0x9844, 0x2900, + 0x3a40, 0x0000, 0x3508, 0x2911, 0xf140, 0x0000, 0x0024, 0x0030, 0x0057, + 0x3700, 0x0024, 0xf200, 0x4595, 0x0fff, 0xfe02, 0xa024, 0x164c, 0x8000, + 0x17cc, 0x3f00, 0x0024, 0x3500, 0x0024, 0x0021, 0x6d82, 0xd024, 0x44c0, + 0x0006, 0xa402, 0x2800, 0x3955, 0xd024, 0x0024, 0x0000, 0x0000, 0x2800, + 0x3955, 0x000b, 0x6d57, 0x3009, 0x3c00, 0x36f0, 0x8024, 0x36f2, 0x1800, + 0x2000, 0x0000, 0x0000, 0x0024, 0x3e14, 0x7810, 0x3e13, 0xb80d, 0x3e13, + 0xf80a, 0x3e10, 0xb803, 0x3e11, 0x3805, 0x3e11, 0xb807, 0x3e14, 0xf801, + 0x3e15, 0x3815, 0x0001, 0x000a, 0x0006, 0xc4d7, 0xbf8e, 0x9c42, 0x3e01, + 0x9c03, 0x0006, 0xa017, 0x0023, 0xffd1, 0x0007, 0x8250, 0x0fff, 0xfd85, + 0x3001, 0x0024, 0xa45a, 0x4494, 0x0000, 0x0093, 0x2800, 0x4091, 0xf25a, + 0x104c, 0x34f3, 0x0024, 0x2800, 0x4091, 0x0000, 0x0024, 0x3413, 0x084c, + 0x0000, 0x0095, 0x3281, 0xf806, 0x4091, 0x4d64, 0x2400, 0x42c0, 0x4efa, + 0x9c10, 0xf1eb, 0x6061, 0xfe55, 0x2f66, 0x5653, 0x4d64, 0x48b2, 0xa201, + 0x4efa, 0xa201, 0x36f3, 0x3c10, 0x36f5, 0x1815, 0x36f4, 0xd801, 0x36f1, + 0x9807, 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f3, 0xd80a, 0x36f3, 0x980d, + 0x2000, 0x0000, 0x36f4, 0x5810, 0x36f3, 0x0024, 0x3009, 0x3848, 0x3e14, + 0x3811, 0x3e00, 0x0024, 0x0000, 0x4000, 0x0001, 0x0010, 0x2915, 0x94c0, + 0x0001, 0xcc11, 0x36f0, 0x0024, 0x2927, 0x9e40, 0x3604, 0x1811, 0x3613, + 0x0024, 0x3e14, 0x3811, 0x3e00, 0x0024, 0x0000, 0x4000, 0x0001, 0x0010, + 0x2915, 0x94c0, 0x0001, 0xcc11, 0x36f0, 0x0024, 0x36f4, 0x1811, 0x3009, + 0x1808, 0x2000, 0x0000, 0x0000, 0x190d, 0x3613, 0x0024, 0x3e22, 0xb815, + 0x3e05, 0xb814, 0x3615, 0x0024, 0x0000, 0x800a, 0x3e13, 0x7801, 0x3e10, + 0xb803, 0x3e11, 0x3805, 0x3e11, 0xb807, 0x3e14, 0x3811, 0x3e14, 0xb813, + 0x3e03, 0xf80e, 0xb488, 0x44d5, 0x3543, 0x134c, 0x34e5, 0xc024, 0x3524, + 0x8024, 0x35a4, 0xc024, 0x3710, 0x8a0c, 0x3540, 0x4a0c, 0x3d44, 0x8024, + 0x3a10, 0x8024, 0x3590, 0x0024, 0x4010, 0x15c1, 0x6010, 0x3400, 0x3710, + 0x8024, 0x2800, 0x5704, 0x3af0, 0x8024, 0x3df0, 0x0024, 0x3591, 0x4024, + 0x3530, 0x4024, 0x4192, 0x4050, 0x6100, 0x1482, 0x4020, 0x1753, 0xbf8e, + 0x1582, 0x4294, 0x4011, 0xbd86, 0x408e, 0x2400, 0x550e, 0xfe6d, 0x2819, + 0x520e, 0x0a00, 0x5207, 0x2819, 0x4fbe, 0x0024, 0xad56, 0x904c, 0xaf5e, + 0x1010, 0xf7d4, 0x0024, 0xf7fc, 0x2042, 0x6498, 0x2046, 0x3cf4, 0x0024, + 0x3400, 0x170c, 0x4090, 0x1492, 0x35a4, 0xc024, 0x2800, 0x4f95, 0x3c00, + 0x0024, 0x4480, 0x914c, 0x36f3, 0xd80e, 0x36f4, 0x9813, 0x36f4, 0x1811, + 0x36f1, 0x9807, 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f3, 0x5801, 0x3405, + 0x9014, 0x36e3, 0x0024, 0x2000, 0x0000, 0x36f2, 0x9815, 0x0000, 0x0200, + 0xb386, 0x3803, 0xad06, 0x0024, 0x2000, 0x0000, 0xc320, 0x1bc3, 0x2814, + 0x9c91, 0x0000, 0x004d, 0x2814, 0x9940, 0x003f, 0x0013, 0x3e12, 0xb817, + 0x3e12, 0x7808, 0x3e11, 0xb811, 0x3e15, 0x7810, 0x3e18, 0xb823, 0x3e18, + 0x3821, 0x3e10, 0x3801, 0x48b2, 0x0024, 0x3e10, 0x3801, 0x3e11, 0x3802, + 0x3009, 0x3814, 0x0030, 0x0717, 0x3f05, 0xc024, 0x0030, 0x0351, 0x3100, + 0x0024, 0x4080, 0x0024, 0x0030, 0x10d1, 0x2800, 0x6885, 0x0001, 0x800a, + 0x0006, 0x6514, 0x3111, 0x8024, 0x6894, 0x13c1, 0x6618, 0x0024, 0xfe44, + 0x1000, 0x4cb2, 0x0406, 0x3c10, 0x0024, 0x3c50, 0x4024, 0x34f0, 0x4024, + 0x661c, 0x1040, 0xfe64, 0x0024, 0x4cb2, 0x0024, 0x3cf0, 0x4024, 0xbc82, + 0x3080, 0x0030, 0x0351, 0x3100, 0x8024, 0xfea8, 0x0024, 0x5ca2, 0x0024, + 0x0000, 0x0182, 0xac22, 0x0024, 0xf7c8, 0x0024, 0x48b2, 0x0024, 0xac22, + 0x0024, 0x2800, 0x6c00, 0xf7cc, 0x1002, 0x0030, 0x0394, 0x3400, 0x4024, + 0x3100, 0x184c, 0x0006, 0xc051, 0x291e, 0x8080, 0x0006, 0x6410, 0x4088, + 0x1001, 0x0030, 0x1111, 0x3100, 0x184c, 0x0006, 0xc051, 0x291e, 0x8080, + 0x0006, 0x6550, 0x0006, 0x6694, 0x408c, 0x1002, 0xf224, 0x0024, 0x0006, + 0xa017, 0x2800, 0x7015, 0x0000, 0x0024, 0x2808, 0x3f41, 0x0006, 0x6410, + 0x3050, 0x0024, 0x3000, 0x4024, 0x6014, 0x0024, 0x0000, 0x0024, 0x2800, + 0x6f59, 0x0000, 0x0024, 0xf400, 0x4040, 0x38b0, 0x0024, 0x2808, 0x3f40, + 0x3800, 0x0024, 0x2800, 0x7201, 0xf224, 0x0024, 0x0000, 0x0024, 0x2808, + 0x3f45, 0x4684, 0x4106, 0xf12c, 0x0024, 0xf148, 0x0024, 0x846c, 0x0024, + 0x2808, 0x3f40, 0xf400, 0x4184, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, + 0xb814, 0x3625, 0x0024, 0x0000, 0x800a, 0x3e10, 0x3801, 0x3e10, 0xb803, + 0x3e11, 0x3805, 0x3e11, 0xb807, 0x3e14, 0x3811, 0x0006, 0xa090, 0x2912, + 0x0d00, 0x3e14, 0xc024, 0x4088, 0x8000, 0x4080, 0x0024, 0x0007, 0x90d1, + 0x2800, 0x7845, 0x0000, 0x0024, 0x0007, 0x9051, 0x3100, 0x4024, 0x4100, + 0x0024, 0x3900, 0x0024, 0x0007, 0x90d1, 0x0004, 0x0000, 0x31f0, 0x4024, + 0x6014, 0x0400, 0x0000, 0x0024, 0x2800, 0x7c91, 0x4080, 0x0024, 0x0000, + 0x0000, 0x2800, 0x7c05, 0x0000, 0x0024, 0x0007, 0x9053, 0x3300, 0x0024, + 0x4080, 0x0024, 0x0000, 0x0000, 0x2800, 0x7c98, 0x0000, 0x0024, 0x0007, + 0x9051, 0x3900, 0x0024, 0x3200, 0x504c, 0x6410, 0x0024, 0x3cf0, 0x0000, + 0x4080, 0x0024, 0x0006, 0xc691, 0x2800, 0x9545, 0x3009, 0x0400, 0x0000, + 0x1001, 0x0007, 0x9051, 0x3100, 0x0024, 0x6012, 0x0024, 0x0006, 0xc6d0, + 0x2800, 0x8989, 0x003f, 0xe000, 0x0006, 0xc693, 0x3900, 0x0c00, 0x3009, + 0x0001, 0x6014, 0x0024, 0x0007, 0x1ad0, 0x2800, 0x8995, 0x3009, 0x0000, + 0x4080, 0x0024, 0x0000, 0x0301, 0x2800, 0x8385, 0x4090, 0x0024, 0x0000, + 0x0024, 0x2800, 0x8495, 0x0000, 0x0024, 0x3009, 0x0000, 0xc012, 0x0024, + 0x2800, 0x8980, 0x3009, 0x2001, 0x3009, 0x0000, 0x6012, 0x0024, 0x0000, + 0x0341, 0x2800, 0x8695, 0x0000, 0x0024, 0x6190, 0x0024, 0x2800, 0x8980, + 0x3009, 0x2000, 0x6012, 0x0024, 0x0000, 0x0381, 0x2800, 0x8855, 0x0000, + 0x0024, 0x6190, 0x0024, 0x2800, 0x8980, 0x3009, 0x2000, 0x6012, 0x0024, + 0x0000, 0x00c0, 0x2800, 0x8995, 0x0000, 0x0024, 0x3009, 0x2000, 0x0006, + 0xa090, 0x3009, 0x0000, 0x4080, 0x0024, 0x0000, 0x0081, 0x2800, 0x8e55, + 0x0007, 0x8c13, 0x3300, 0x104c, 0xb010, 0x0024, 0x0002, 0x8001, 0x2800, + 0x90c5, 0x34f0, 0x0024, 0x2800, 0x8e40, 0x0000, 0x0024, 0x0006, 0xc351, + 0x3009, 0x0000, 0x6090, 0x0024, 0x3009, 0x2000, 0x2900, 0x0b80, 0x3009, + 0x0405, 0x0006, 0xc6d1, 0x0006, 0xc690, 0x3009, 0x0000, 0x3009, 0x0401, + 0x6014, 0x0024, 0x0006, 0xa093, 0x2800, 0x8cd1, 0xb880, 0x0024, 0x2800, + 0x9e00, 0x3009, 0x2c00, 0x4040, 0x0024, 0x6012, 0x0024, 0x0006, 0xc6d0, + 0x2800, 0x9e18, 0x0000, 0x0024, 0x0006, 0xc693, 0x3009, 0x0c00, 0x3009, + 0x0001, 0x6014, 0x0024, 0x0006, 0xc350, 0x2800, 0x9e01, 0x0000, 0x0024, + 0x6090, 0x0024, 0x3009, 0x2c00, 0x3009, 0x0005, 0x2900, 0x0b80, 0x0000, + 0x9e08, 0x3009, 0x0400, 0x4080, 0x0024, 0x0003, 0x8000, 0x2800, 0x9e05, + 0x0000, 0x0024, 0x6400, 0x0024, 0x0000, 0x0081, 0x2800, 0x9e09, 0x0000, + 0x0024, 0x0007, 0x8c13, 0x3300, 0x0024, 0xb010, 0x0024, 0x0006, 0xc650, + 0x2800, 0x9e15, 0x0000, 0x0024, 0x0001, 0x0002, 0x3413, 0x0000, 0x3009, + 0x0401, 0x4010, 0x8406, 0x0000, 0x0281, 0xa010, 0x13c1, 0x4122, 0x0024, + 0x0000, 0x03c2, 0x6122, 0x8002, 0x462c, 0x0024, 0x469c, 0x0024, 0xfee2, + 0x0024, 0x48be, 0x0024, 0x6066, 0x8400, 0x0006, 0xc350, 0x2800, 0x9e01, + 0x0000, 0x0024, 0x4090, 0x0024, 0x3009, 0x2400, 0x2900, 0x0b80, 0x3009, + 0x0005, 0x0007, 0x1b50, 0x2912, 0x0d00, 0x3613, 0x0024, 0x3a00, 0x0380, + 0x4080, 0x0024, 0x0000, 0x00c1, 0x2800, 0xa6c5, 0x3009, 0x0000, 0xb010, + 0x008c, 0x4192, 0x0024, 0x6012, 0x0024, 0x0006, 0xf051, 0x2800, 0xa4d8, + 0x3009, 0x0400, 0x0007, 0x1fd1, 0x30e3, 0x0400, 0x4080, 0x0024, 0x0000, + 0x0301, 0x2800, 0xa6c5, 0x3009, 0x0000, 0xb010, 0x0024, 0x0000, 0x0101, + 0x6012, 0x0024, 0x0006, 0xf051, 0x2800, 0xa6d5, 0x0000, 0x0024, 0x3023, + 0x0400, 0xf200, 0x184c, 0xb880, 0xa400, 0x3009, 0x2000, 0x3009, 0x0441, + 0x3e10, 0x4402, 0x2909, 0xa9c0, 0x3e10, 0x8024, 0x36e3, 0x0024, 0x36f4, + 0xc024, 0x36f4, 0x1811, 0x36f1, 0x9807, 0x36f1, 0x1805, 0x36f0, 0x9803, + 0x36f0, 0x1801, 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, + 0x0000, 0x36f2, 0x9817, 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, + 0x3e05, 0xb814, 0x3615, 0x0024, 0x0000, 0x800a, 0x3e10, 0xb803, 0x3e11, + 0x3805, 0x3e14, 0x3811, 0x3e14, 0x92cc, 0x3400, 0x0024, 0x4080, 0x0024, + 0x0000, 0x0590, 0x2800, 0xb058, 0x0000, 0x0024, 0x6800, 0x9bcc, 0x3c20, + 0x0024, 0x34e4, 0x4024, 0x3410, 0x860c, 0x3100, 0x0024, 0xff20, 0x1012, + 0x48b6, 0x084c, 0x4280, 0x1110, 0x6898, 0x0024, 0x2900, 0xb480, 0x0000, + 0x0085, 0x34b3, 0x184c, 0x3410, 0x0024, 0x3e10, 0x0024, 0x3410, 0x0024, + 0x3e10, 0x0024, 0x3430, 0x0024, 0x2920, 0x1340, 0x3e00, 0x0024, 0x36d3, + 0x0024, 0x36f4, 0x8024, 0x36f4, 0x1811, 0x36f1, 0x1805, 0x36f0, 0x9803, + 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, + 0x9817, 0x4090, 0x184c, 0x3e14, 0xf811, 0x3e13, 0xf80e, 0x2800, 0xb6c4, + 0x3e03, 0x4024, 0x2400, 0xb680, 0x2b11, 0x1153, 0x3280, 0x0024, 0x3880, + 0x0024, 0x36f3, 0x4024, 0x36f3, 0xd80e, 0x2000, 0x0000, 0x36f4, 0xd811, + 0x4090, 0x184c, 0x3e14, 0xf811, 0x3e13, 0xf80e, 0x2800, 0xbac4, 0x4498, + 0x380d, 0x459a, 0x0024, 0x2400, 0xba80, 0x2b11, 0x1153, 0x3210, 0x0024, + 0x3810, 0x0024, 0x3280, 0x0024, 0x3880, 0x0024, 0x36f3, 0x4024, 0x36f3, + 0xd80e, 0x2000, 0x0000, 0x36f4, 0xd811, 0x3613, 0x0024, 0x3e22, 0xb815, + 0x3e05, 0xb814, 0xb880, 0x1854, 0x3405, 0x9014, 0x36e3, 0x0024, 0x2000, + 0x0000, 0x36f2, 0x9815, 0x3613, 0x0024, 0x3e22, 0xb815, 0x3e05, 0xb814, + 0x3615, 0x0024, 0x3405, 0x9014, 0x36e3, 0x0024, 0x2000, 0x0000, 0x36f2, + 0x9815, 0x0007, 0x0001, /*copy 1*/ + 0x8300, 0x0006, 0x191c, /*copy 6428*/ + 0x0030, 0x0055, 0xb080, 0x1402, 0x0fdf, 0xffc1, 0x0007, 0x9257, 0xb212, + 0x3c00, 0x3d00, 0x4024, 0x0006, 0x0097, 0x3f10, 0x0024, 0x3f00, 0x0024, + 0x0030, 0x0297, 0x3f00, 0x0024, 0x0007, 0x9017, 0x3f00, 0x0024, 0x0007, + 0x81d7, 0x3f10, 0x0024, 0xc090, 0x3c00, 0x0006, 0x0297, 0xb080, 0x3c00, + 0x0000, 0x0401, 0x000a, 0x1055, 0x0006, 0x0017, 0x3f10, 0x3401, 0x000a, + 0x2795, 0x3f00, 0x3401, 0x0001, 0x69d7, 0xf400, 0x55c0, 0x0000, 0x0817, + 0xb080, 0x57c0, 0x0014, 0x958f, 0x0000, 0x5c8e, 0x0030, 0x0017, 0x3700, + 0x0024, 0x0004, 0x0001, 0xb012, 0x0024, 0x0000, 0x004d, 0x280f, 0xe115, + 0x0006, 0x2016, 0x0006, 0x01d7, 0x3f00, 0x0024, 0x0000, 0x190d, 0x000f, + 0xf94f, 0x0000, 0xcd0e, 0x280f, 0xe100, 0x0006, 0x2016, 0x0000, 0x0080, + 0x0005, 0x4f92, 0x2909, 0xf840, 0x3613, 0x2800, 0x0006, 0x0197, 0x0006, + 0xa115, 0xb080, 0x0024, 0x3f00, 0x3400, 0x0007, 0x8a57, 0x3700, 0x0024, + 0x4080, 0x0024, 0x0000, 0x0040, 0x2800, 0xced5, 0x0006, 0xa2d7, 0x3009, + 0x3c00, 0x0006, 0xa157, 0x3009, 0x1c00, 0x0006, 0x01d7, 0x0000, 0x190d, + 0x000a, 0x708f, 0x0000, 0xd7ce, 0x290b, 0x1a80, 0x3f00, 0x184c, 0x0030, + 0x0017, 0x4080, 0x1c01, 0x0000, 0x0200, 0x2800, 0xcb15, 0xb102, 0x0024, + 0x0000, 0xcd08, 0x2800, 0xcb15, 0x0000, 0xd3ce, 0x0011, 0x210f, 0x0000, + 0x190d, 0x280f, 0xcb00, 0x3613, 0x0024, 0x0006, 0xa115, 0x0006, 0x01d7, + 0x37f0, 0x1401, 0x6100, 0x1c01, 0x4012, 0x0024, 0x0000, 0x8000, 0x6010, + 0x0024, 0x34f3, 0x0400, 0x2800, 0xd698, 0x0000, 0x0024, 0x0000, 0x8001, + 0x6010, 0x3c01, 0x0000, 0x000d, 0x2811, 0x8259, 0x0000, 0x0024, 0x2a11, + 0x2100, 0x0030, 0x0257, 0x3700, 0x0024, 0x4080, 0x0024, 0x0000, 0x0024, + 0x2800, 0xd9d5, 0x0006, 0x0197, 0x0006, 0xa115, 0x3f00, 0x3400, 0x4d86, + 0x0024, 0x0000, 0x190d, 0x2800, 0xdd55, 0x0014, 0x1b01, 0x0020, 0x480f, + 0x0000, 0xdc0e, 0x0000, 0x190d, 0x2820, 0x41c0, 0x0001, 0x10c8, 0x0039, + 0x324f, 0x0001, 0x3dce, 0x2820, 0x4a18, 0xb882, 0x0024, 0x2a20, 0x48c0, + 0x003f, 0xfd00, 0xb700, 0x0024, 0x003f, 0xf901, 0x6010, 0x0024, 0x0000, + 0x0024, 0x280a, 0xc505, 0x0000, 0x190d, 0x0014, 0x1b01, 0x0015, 0x59c0, + 0x6fc2, 0x0024, 0x0000, 0x0024, 0x2800, 0xe795, 0x0000, 0x0024, 0x290c, + 0x4840, 0x3613, 0x0024, 0x290c, 0x4840, 0x4086, 0x184c, 0x0000, 0x18c2, + 0x6234, 0x0024, 0x0000, 0x1d02, 0x2800, 0xe395, 0x6234, 0x0024, 0x0030, + 0x0317, 0x2800, 0xe780, 0x3f00, 0x0024, 0x0000, 0x1d82, 0x2800, 0xe615, + 0x6234, 0x0024, 0x2912, 0x0d00, 0x4084, 0x184c, 0xf200, 0x0024, 0x6200, + 0x0024, 0x0006, 0x0017, 0x2800, 0xe300, 0xb080, 0x3c40, 0x0000, 0x0202, + 0x2800, 0xe795, 0xa024, 0x0024, 0xc020, 0x0024, 0x2800, 0xe300, 0x0030, + 0x02d7, 0x0011, 0x14c1, 0x0011, 0x0800, 0x6fc2, 0x0024, 0x0011, 0x9481, + 0x2800, 0xea05, 0x0013, 0x4e00, 0x6fc2, 0x0024, 0x0000, 0x0024, 0x2800, + 0xea95, 0x0000, 0x0024, 0x2801, 0x8ec0, 0x000a, 0xcac8, 0x000a, 0x8c8f, + 0x0000, 0xebce, 0x000c, 0x0981, 0x280a, 0x71c0, 0x002c, 0x9d40, 0x000a, + 0x708f, 0x0000, 0xd7ce, 0x280a, 0xc0d5, 0x0012, 0x5182, 0x6fd6, 0x0024, + 0x003f, 0xfd81, 0x280a, 0x8e45, 0xb710, 0x0024, 0xb710, 0x0024, 0x003f, + 0xfc01, 0x6012, 0x0024, 0x0000, 0x0101, 0x2801, 0x0795, 0xffd2, 0x0024, + 0x48b2, 0x0024, 0x4190, 0x0024, 0x0000, 0x190d, 0x2801, 0x0795, 0x0030, + 0x0250, 0xb880, 0x104c, 0x3cf0, 0x0024, 0x0010, 0x5500, 0xb880, 0x23c0, + 0xb882, 0x2000, 0x0007, 0x8590, 0x2914, 0xbec0, 0x0000, 0x0440, 0x0007, + 0x8b50, 0xb880, 0x0024, 0x2920, 0x0100, 0x3800, 0x0024, 0x2920, 0x0000, + 0x0006, 0x8a91, 0x0000, 0x0800, 0xb880, 0xa440, 0x003f, 0xfd81, 0xb710, + 0xa7c0, 0x003f, 0xfc01, 0x6012, 0x0024, 0x0000, 0x0101, 0x2801, 0x10d5, + 0x0000, 0x0024, 0xffe2, 0x0024, 0x48b2, 0x0024, 0x4190, 0x0024, 0x0000, + 0x0024, 0x2801, 0x10d5, 0x0000, 0x0024, 0x2912, 0x2d80, 0x0000, 0x0780, + 0x4080, 0x0024, 0x0006, 0x8a90, 0x2801, 0x10d5, 0x0000, 0x01c2, 0xb886, + 0x8040, 0x3613, 0x03c1, 0xbcd2, 0x0024, 0x0030, 0x0011, 0x2800, 0xfd55, + 0x003f, 0xff42, 0xb886, 0x8040, 0x3009, 0x03c1, 0x0000, 0x0020, 0xac22, + 0x0024, 0x0000, 0x0102, 0x6cd2, 0x0024, 0x3e10, 0x0024, 0x2909, 0x8c80, + 0x3e00, 0x4024, 0x36f3, 0x0024, 0x3e11, 0x8024, 0x3e01, 0xc024, 0x2901, + 0x3480, 0x0000, 0x0201, 0xf400, 0x4512, 0x2900, 0x0c80, 0x3213, 0x1b8c, + 0x3100, 0x0024, 0xb010, 0x0024, 0x0000, 0x0024, 0x2801, 0x10d5, 0x0000, + 0x0024, 0x291a, 0x8a40, 0x0000, 0x0100, 0x2920, 0x0200, 0x3633, 0x0024, + 0x2920, 0x0280, 0x0000, 0x0401, 0x408e, 0x0024, 0x2920, 0x0280, 0x0000, + 0x0401, 0x003f, 0xfd81, 0xb710, 0x4006, 0x003f, 0xfc01, 0x6012, 0x0024, + 0x0000, 0x0101, 0x2801, 0x10d5, 0x0000, 0x0024, 0xffe2, 0x0024, 0x48b2, + 0x0024, 0x4190, 0x0024, 0x0000, 0x0024, 0x2801, 0x10d5, 0x0000, 0x0024, + 0x2912, 0x2d80, 0x0000, 0x0780, 0x4080, 0x0024, 0x0000, 0x01c2, 0x2800, + 0xf945, 0x0006, 0x8a90, 0x2a01, 0x10c0, 0x2920, 0x0100, 0x0000, 0x0401, + 0x0000, 0x0180, 0x2920, 0x0200, 0x3613, 0x0024, 0x2920, 0x0280, 0x3613, + 0x0024, 0x0000, 0x0401, 0x2920, 0x0280, 0x4084, 0x984c, 0x0019, 0x9d01, + 0x6212, 0x0024, 0x001e, 0x5c01, 0x2801, 0x0c15, 0x6012, 0x0024, 0x0000, + 0x0024, 0x2801, 0x0e05, 0x0000, 0x0024, 0x001b, 0x5bc1, 0x6212, 0x0024, + 0x001b, 0xdd81, 0x2801, 0x11d5, 0x6012, 0x0024, 0x0000, 0x0024, 0x2801, + 0x11d5, 0x0000, 0x0024, 0x0000, 0x004d, 0x000a, 0xbf4f, 0x280a, 0xb880, + 0x0001, 0x0f0e, 0x0020, 0xfb4f, 0x0000, 0x190d, 0x0001, 0x160e, 0x2920, + 0xf440, 0x3009, 0x2bc1, 0x291a, 0x8a40, 0x36e3, 0x0024, 0x0000, 0x190d, + 0x000a, 0x708f, 0x280a, 0xcac0, 0x0000, 0xd7ce, 0x0030, 0x0017, 0x3700, + 0x4024, 0x0000, 0x0200, 0xb102, 0x0024, 0x0000, 0x00c0, 0x2801, 0x1505, + 0x0005, 0x4f92, 0x2909, 0xf840, 0x3613, 0x2800, 0x0006, 0x0197, 0x0006, + 0xa115, 0xb080, 0x0024, 0x3f00, 0x3400, 0x0000, 0x190d, 0x000a, 0x708f, + 0x280a, 0xc0c0, 0x0000, 0xd7ce, 0x0000, 0x004d, 0x0020, 0xfe0f, 0x2820, + 0xfb40, 0x0001, 0x170e, 0x2801, 0x18d5, 0x3009, 0x1000, 0x6012, 0x93cc, + 0x0000, 0x0024, 0x2801, 0x3385, 0x0000, 0x0024, 0x3413, 0x0024, 0x34b0, + 0x0024, 0x4080, 0x0024, 0x0000, 0x0200, 0x2801, 0x1bd5, 0xb882, 0x0024, + 0x3453, 0x0024, 0x3009, 0x13c0, 0x4080, 0x0024, 0x0000, 0x0200, 0x2801, + 0x3385, 0x0000, 0x0024, 0xb882, 0x130c, 0x0000, 0x004d, 0x0021, 0x058f, + 0x2821, 0x0340, 0x0001, 0x1cce, 0x2801, 0x2d15, 0x6012, 0x0024, 0x0000, + 0x0024, 0x2801, 0x2d15, 0x0000, 0x0024, 0x34c3, 0x184c, 0x3e13, 0xb80f, + 0xf400, 0x4500, 0x0026, 0x9dcf, 0x0001, 0x20ce, 0x0000, 0xfa0d, 0x2926, + 0x8e80, 0x3e10, 0x110c, 0x36f3, 0x0024, 0x2801, 0x2d00, 0x36f3, 0x980f, + 0x001c, 0xdd00, 0x001c, 0xd901, 0x6ec2, 0x0024, 0x001c, 0xdd00, 0x2801, + 0x23d5, 0x0018, 0xdbc1, 0x3413, 0x184c, 0xf400, 0x4500, 0x2926, 0xc640, + 0x3e00, 0x13cc, 0x2801, 0x2ac0, 0x36f3, 0x0024, 0x6ec2, 0x0024, 0x003f, + 0xc000, 0x2801, 0x2655, 0x002a, 0x4001, 0x3413, 0x184c, 0xf400, 0x4500, + 0x2926, 0xafc0, 0x3e00, 0x13cc, 0x2801, 0x2ac0, 0x36f3, 0x0024, 0xb400, + 0x0024, 0xd100, 0x0024, 0x0000, 0x0024, 0x2801, 0x2ac5, 0x0000, 0x0024, + 0x3613, 0x0024, 0x3e11, 0x4024, 0x2926, 0x8540, 0x3e01, 0x0024, 0x4080, + 0x1b8c, 0x0000, 0x0024, 0x2801, 0x2ac5, 0x0000, 0x0024, 0x3413, 0x184c, + 0xf400, 0x4500, 0x2926, 0x8e80, 0x3e10, 0x13cc, 0x36f3, 0x0024, 0x3110, + 0x8024, 0x31f0, 0xc024, 0x0000, 0x4000, 0x0000, 0x0021, 0x6d06, 0x0024, + 0x3110, 0x8024, 0x2826, 0xa8c4, 0x31f0, 0xc024, 0x2a26, 0xad00, 0x34c3, + 0x184c, 0x3410, 0x8024, 0x3430, 0xc024, 0x0000, 0x4000, 0x0000, 0x0021, + 0x6d06, 0x0024, 0x0000, 0x0024, 0x2801, 0x3394, 0x4d06, 0x0024, 0x0000, + 0x0200, 0x2922, 0x1885, 0x0001, 0x3208, 0x0000, 0x0200, 0x3e10, 0x8024, + 0x2921, 0xca80, 0x3e00, 0xc024, 0x291a, 0x8a40, 0x0000, 0x0024, 0x2922, + 0x1880, 0x36f3, 0x0024, 0x0000, 0x004d, 0x0021, 0x0ecf, 0x2821, 0x0bc0, + 0x0001, 0x330e, 0x2801, 0x1600, 0x3c30, 0x4024, 0x0000, 0x190d, 0x0000, + 0x458e, 0x2821, 0x0f80, 0x0027, 0x9e0f, 0x0020, 0xcd4f, 0x2820, 0xc780, + 0x0001, 0x354e, 0x0006, 0xf017, 0x0000, 0x0015, 0xb070, 0xbc15, 0x0000, + 0x458e, 0x0027, 0x9e0f, 0x2820, 0xcd80, 0x0000, 0x190d, 0x3613, 0x0024, + 0x3e10, 0xb803, 0x3e14, 0x3811, 0x3e11, 0x3805, 0x3e00, 0x3801, 0x0007, + 0xc390, 0x0006, 0xa011, 0x3010, 0x0444, 0x3050, 0x4405, 0x6458, 0x0302, + 0xff94, 0x4081, 0x0003, 0xffc5, 0x48b6, 0x0024, 0xff82, 0x0024, 0x42b2, + 0x0042, 0xb458, 0x0003, 0x4cd6, 0x9801, 0xf248, 0x1bc0, 0xb58a, 0x0024, + 0x6de6, 0x1804, 0x0006, 0x0010, 0x3810, 0x9bc5, 0x3800, 0xc024, 0x36f4, + 0x1811, 0x36f0, 0x9803, 0x283e, 0x2d80, 0x0fff, 0xffc3, 0x2801, 0x4b80, + 0x0000, 0x0024, 0x3413, 0x0024, 0x2801, 0x3f85, 0xf400, 0x4517, 0x2801, + 0x4380, 0x6894, 0x13cc, 0x37b0, 0x184c, 0x6090, 0x1d51, 0x0000, 0x0910, + 0x3f00, 0x060c, 0x3100, 0x4024, 0x6016, 0xb812, 0x000c, 0x8012, 0x2801, + 0x4211, 0xb884, 0x0024, 0x6894, 0x3002, 0x0000, 0x028d, 0x003a, 0x5e0f, + 0x0001, 0x538e, 0x2939, 0xb0c0, 0x3e10, 0x93cc, 0x4084, 0x9bd2, 0x4282, + 0x0024, 0x0000, 0x0040, 0x2801, 0x4585, 0x4292, 0x130c, 0x3443, 0x0024, + 0x2801, 0x46c5, 0x000c, 0x8390, 0x2a01, 0x4a40, 0x3444, 0x0024, 0x3073, + 0x0024, 0xc090, 0x014c, 0x2801, 0x4a40, 0x3800, 0x0024, 0x000c, 0x4113, + 0xb880, 0x2380, 0x3304, 0x4024, 0x3800, 0x05cc, 0xcc92, 0x05cc, 0x3910, + 0x0024, 0x3910, 0x4024, 0x000c, 0x8110, 0x3910, 0x0024, 0x39f0, 0x4024, + 0x3810, 0x0024, 0x38d0, 0x4024, 0x3810, 0x0024, 0x38f0, 0x4024, 0x34c3, + 0x0024, 0x3444, 0x0024, 0x3073, 0x0024, 0x3063, 0x0024, 0x3000, 0x0024, + 0x4080, 0x0024, 0x0000, 0x0024, 0x2839, 0x53d5, 0x4284, 0x0024, 0x3613, + 0x0024, 0x2801, 0x4d85, 0x6898, 0xb804, 0x0000, 0x0084, 0x293b, 0x1cc0, + 0x3613, 0x0024, 0x000c, 0x8117, 0x3711, 0x0024, 0x37d1, 0x4024, 0x4e8a, + 0x0024, 0x0000, 0x0015, 0x2801, 0x5045, 0xce9a, 0x0024, 0x3f11, 0x0024, + 0x3f01, 0x4024, 0x000c, 0x8197, 0x408a, 0x9bc4, 0x3f15, 0x4024, 0x2801, + 0x5285, 0x4284, 0x3c15, 0x6590, 0x0024, 0x0000, 0x0024, 0x2839, 0x53d5, + 0x4284, 0x0024, 0x0000, 0x0024, 0x2801, 0x3e58, 0x458a, 0x0024, 0x2a39, + 0x53c0, 0x003e, 0x2d4f, 0x283a, 0x5ed5, 0x0001, 0x370e, 0x000c, 0x4653, + 0x0000, 0x0246, 0xffac, 0x0c01, 0x48be, 0x0024, 0x4162, 0x4546, 0x6642, + 0x4055, 0x3501, 0x8024, 0x0000, 0x0087, 0x667c, 0x4057, 0x000c, 0x41d5, + 0x283a, 0x62d5, 0x3501, 0x8024, 0x667c, 0x1c47, 0x3701, 0x8024, 0x283a, + 0x62d5, 0xc67c, 0x0024, 0x0000, 0x0024, 0x283a, 0x62c5, 0x0000, 0x0024, + 0x2a3a, 0x5ec0, 0x3009, 0x3851, 0x3e14, 0xf812, 0x3e12, 0xb817, 0x3e11, + 0x8024, 0x0006, 0x0293, 0x3301, 0x8024, 0x468c, 0x3804, 0x0006, 0xa057, + 0x2801, 0x5f84, 0x0006, 0x0011, 0x469c, 0x0024, 0x3be1, 0x8024, 0x2801, + 0x5f95, 0x0006, 0xc392, 0x3311, 0x0024, 0x33f1, 0x2844, 0x3009, 0x2bc4, + 0x0030, 0x04d2, 0x3311, 0x0024, 0x3a11, 0x0024, 0x3201, 0x8024, 0x003f, + 0xfc04, 0xb64c, 0x0fc4, 0xc648, 0x0024, 0x3a01, 0x0024, 0x3111, 0x1fd3, + 0x6498, 0x07c6, 0x868c, 0x2444, 0x0023, 0xffd2, 0x3901, 0x8e06, 0x0030, + 0x0551, 0x3911, 0x8e06, 0x3961, 0x9c44, 0xf400, 0x44c6, 0xd46c, 0x1bc4, + 0x36f1, 0xbc13, 0x2801, 0x6915, 0x36f2, 0x9817, 0x002b, 0xffd2, 0x3383, + 0x188c, 0x3e01, 0x8c06, 0x0006, 0xa097, 0x3009, 0x1c12, 0x3213, 0x0024, + 0x468c, 0xbc12, 0x002b, 0xffd2, 0xf400, 0x4197, 0x2801, 0x6604, 0x3713, + 0x0024, 0x2801, 0x6645, 0x37e3, 0x0024, 0x3009, 0x2c17, 0x3383, 0x0024, + 0x3009, 0x0c06, 0x468c, 0x4197, 0x0006, 0xa052, 0x2801, 0x6844, 0x3713, + 0x2813, 0x2801, 0x6885, 0x37e3, 0x0024, 0x3009, 0x2c17, 0x36f1, 0x8024, + 0x36f2, 0x9817, 0x36f4, 0xd812, 0x2100, 0x0000, 0x3904, 0x5bd1, 0x2a01, + 0x594e, 0x3e11, 0x7804, 0x0030, 0x0257, 0x3701, 0x0024, 0x0013, 0x4d05, + 0xd45b, 0xe0e1, 0x0007, 0xc795, 0x2801, 0x7095, 0x0fff, 0xff45, 0x3511, + 0x184c, 0x4488, 0xb808, 0x0006, 0x8a97, 0x2801, 0x7045, 0x3009, 0x1c40, + 0x3511, 0x1fc1, 0x0000, 0x0020, 0xac52, 0x1405, 0x6ce2, 0x0024, 0x0000, + 0x0024, 0x2801, 0x7041, 0x68c2, 0x0024, 0x291a, 0x8a40, 0x3e10, 0x0024, + 0x2921, 0xca80, 0x3e00, 0x4024, 0x36f3, 0x0024, 0x3009, 0x1bc8, 0x36f0, + 0x1801, 0x3601, 0x5804, 0x3e13, 0x780f, 0x3e13, 0xb808, 0x0008, 0x9b0f, + 0x0001, 0x734e, 0x2908, 0x9300, 0x0000, 0x004d, 0x36f3, 0x9808, 0x2000, + 0x0000, 0x36f3, 0x580f, 0x0007, 0x81d7, 0x3711, 0x8024, 0x3711, 0xc024, + 0x3700, 0x0024, 0x0000, 0x2001, 0xb012, 0x0024, 0x0034, 0x0000, 0x2801, + 0x78c5, 0x0000, 0x01c1, 0x3700, 0x0024, 0x0002, 0x0001, 0xb012, 0x0024, + 0x002e, 0xe001, 0x2801, 0x77c5, 0x6512, 0x0024, 0x0034, 0x0000, 0x2801, + 0x78d5, 0x0000, 0x01c1, 0x0030, 0x0117, 0x3f00, 0x0024, 0x0014, 0xc000, + 0x0000, 0x01c1, 0x4fce, 0x0024, 0xffea, 0x0024, 0x48b6, 0x0024, 0x4384, + 0x4097, 0xb886, 0x45c6, 0xfede, 0x0024, 0x4db6, 0x0024, 0x466c, 0x0024, + 0x0006, 0xc610, 0x8dd6, 0x8007, 0x0000, 0x00c6, 0xff6e, 0x0024, 0x48b2, + 0x0024, 0x0034, 0x2406, 0xffee, 0x0024, 0x2914, 0xaa80, 0x40b2, 0x0024, + 0xf1c6, 0x0024, 0xf1d6, 0x0024, 0x0000, 0x0201, 0x8d86, 0x0024, 0x61de, + 0x0024, 0x0006, 0xc612, 0x2801, 0x7f41, 0x0006, 0xc713, 0x4c86, 0x0024, + 0x2912, 0x1180, 0x0006, 0xc351, 0x0006, 0x0210, 0x2912, 0x0d00, 0x3810, + 0x984c, 0xf200, 0x2043, 0x2808, 0xa000, 0x3800, 0x0024, 0x3613, 0x0024, + 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3625, 0x0024, 0x0000, + 0x800a, 0x3e10, 0x7802, 0x3e04, 0x3811, 0x34a3, 0x0024, 0x3470, 0x0024, + 0x2801, 0x88c0, 0x3cf0, 0x0024, 0x0000, 0xfa01, 0x3e10, 0x0024, 0x3410, + 0x0024, 0x3e10, 0x0024, 0x3410, 0x0024, 0x3e10, 0x0024, 0x3430, 0x0024, + 0x2920, 0x0600, 0x3e00, 0x0024, 0x36c3, 0x128c, 0xf400, 0x4510, 0x3420, + 0x0024, 0x6012, 0x4511, 0x3800, 0x4024, 0x0000, 0x7d01, 0x3440, 0x0024, + 0x4012, 0x0024, 0x3900, 0x4024, 0x0000, 0xfa00, 0x34a3, 0x184c, 0x3410, + 0x4024, 0x6014, 0x0024, 0x0000, 0x0024, 0x2801, 0x8451, 0x0000, 0x0024, + 0x3e10, 0x4024, 0x3410, 0x0024, 0x3e10, 0x0024, 0x3410, 0x0024, 0x3e10, + 0x0024, 0x3430, 0x0024, 0x2920, 0x0600, 0x3e00, 0x0024, 0x36c3, 0x104c, + 0x34f0, 0x1811, 0x36f4, 0x0024, 0x36f0, 0x5802, 0x3405, 0x9014, 0x36f3, + 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, 0x0024, + 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3625, 0x0024, 0x0000, + 0x800a, 0x3e10, 0x3801, 0x0000, 0x0081, 0x3e10, 0xb804, 0x3e14, 0x3811, + 0x0006, 0x9f90, 0x3e04, 0xb813, 0x3009, 0x0000, 0x6012, 0x0024, 0x0000, + 0x0000, 0x6104, 0xa001, 0x0000, 0x0940, 0x2801, 0x94c1, 0xb882, 0x0024, + 0x0001, 0x0001, 0x3009, 0x0000, 0x4012, 0x0024, 0x0000, 0x0940, 0xb882, + 0xa001, 0x0000, 0xa992, 0x0007, 0xc051, 0x2914, 0xbec0, 0x0007, 0xc010, + 0x0001, 0x8150, 0x003f, 0xffc0, 0x001f, 0xffc1, 0x3944, 0x0024, 0x0007, + 0xd010, 0x3974, 0x8024, 0x0030, 0x0252, 0x4890, 0x2780, 0x3910, 0x0024, + 0x39d0, 0x4024, 0x3910, 0x0024, 0x2902, 0x0600, 0x39f0, 0x4024, 0x3800, + 0x0024, 0x0011, 0x14c0, 0x3a00, 0x0024, 0x3000, 0x0024, 0x4080, 0x0024, + 0x0000, 0x0024, 0x2801, 0x9d85, 0x0000, 0x0024, 0x3413, 0x184c, 0x2b50, + 0x4013, 0x3e11, 0x0c8c, 0x0007, 0xc004, 0x3e11, 0x13cc, 0x3e00, 0x0024, + 0x3302, 0x0024, 0x2000, 0x0000, 0x0001, 0x9d48, 0x36d3, 0x0024, 0x36f4, + 0x9813, 0x36f4, 0x1811, 0x36f0, 0x9804, 0x36f0, 0x1801, 0x3405, 0x9014, + 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, + 0x0024, 0x3e12, 0xb813, 0x0000, 0x800a, 0x3e10, 0x7802, 0x3e10, 0xf804, + 0x3e11, 0x7806, 0x3e11, 0xf80d, 0x3e13, 0xf80e, 0xf400, 0x4455, 0x6804, + 0x1444, 0xf400, 0x4417, 0x2801, 0xb458, 0x4094, 0x1453, 0x0000, 0x0051, + 0x0fff, 0xff01, 0x2401, 0xb402, 0x3700, 0x8024, 0x003f, 0xc007, 0xb274, + 0x0024, 0xc428, 0x3812, 0x0020, 0x07d2, 0x0003, 0xffc7, 0xb47c, 0x0e0c, + 0x0008, 0x0003, 0x4360, 0x0024, 0xa41c, 0x4010, 0xb67c, 0x0002, 0x4360, + 0x2e02, 0x0000, 0x0206, 0xb58a, 0x1c04, 0xae6a, 0x4010, 0xc548, 0x0002, + 0xb47c, 0x2e02, 0x4360, 0x148c, 0xa41c, 0x4010, 0xb67c, 0x0002, 0x4360, + 0x2e02, 0xf400, 0x4010, 0x3711, 0x3813, 0x0000, 0x3fc6, 0xb468, 0x0000, + 0xb78e, 0x1786, 0x0028, 0x07d2, 0x4ffe, 0x0024, 0x4ffe, 0x1490, 0xbd87, + 0xb80d, 0xfe51, 0x380d, 0x5057, 0x380d, 0x5057, 0x380d, 0x5057, 0x380d, + 0x5057, 0x380d, 0x5057, 0x380d, 0x5057, 0x380d, 0x5057, 0x380d, 0x5057, + 0x380d, 0x5057, 0x380d, 0x5057, 0x380d, 0x505f, 0x380d, 0x505f, 0x380d, + 0x505f, 0x380d, 0x505f, 0x380d, 0x505f, 0x380d, 0x505f, 0x380d, 0x505f, + 0x380d, 0x505f, 0x380d, 0x5057, 0x380d, 0x5057, 0x380d, 0x5057, 0x380d, + 0x5057, 0x380d, 0x5057, 0x380d, 0x5057, 0x380d, 0x5057, 0x380d, 0x5057, + 0x3005, 0x5056, 0x1812, 0x4db6, 0x9813, 0x0fff, 0xff40, 0xad06, 0x0024, + 0x4fde, 0x0024, 0xf1fe, 0x1c02, 0xf1fe, 0x0024, 0xf6fe, 0x3786, 0x3009, + 0x2847, 0x35f3, 0x0024, 0x3df4, 0xc024, 0x3d01, 0x1bcc, 0x36f3, 0xd80e, + 0x36f1, 0xd80d, 0x36f1, 0x5806, 0x36f0, 0xd804, 0x36f0, 0x5802, 0x2000, + 0x0000, 0x36f2, 0x9813, 0x3613, 0x0024, 0x3e12, 0xb813, 0x0000, 0x800a, + 0x3e10, 0x7802, 0x3e10, 0xf804, 0x3e11, 0x7806, 0x3e11, 0xf80d, 0x3e13, + 0xf80e, 0x3009, 0x3854, 0xf400, 0x4455, 0x6804, 0x1444, 0xf400, 0x4417, + 0x2801, 0xcc18, 0x4094, 0x1453, 0x0fff, 0xff01, 0x0000, 0x0051, 0x2401, + 0xcbc2, 0x3700, 0x8024, 0x0fff, 0xfe07, 0xa274, 0x3812, 0x0000, 0x3fc7, + 0xb274, 0x0024, 0x0020, 0x07d2, 0xc428, 0x0e0c, 0xa41c, 0x0024, 0x0003, + 0xffc7, 0xb67c, 0x0024, 0x0008, 0x0003, 0x4360, 0x0024, 0xf400, 0x4010, + 0xb47c, 0x0002, 0x4360, 0x2e02, 0x3701, 0x0024, 0xa41c, 0x4010, 0x3000, + 0x8024, 0xb67c, 0x2e02, 0x4360, 0x948c, 0xf400, 0x4010, 0xb47c, 0x0002, + 0x4360, 0x2e02, 0xf400, 0x4010, 0x3711, 0x3813, 0x0000, 0x0206, 0xa468, + 0x0000, 0xb78e, 0x1786, 0x0028, 0x07d2, 0x4ffe, 0x0024, 0x4ffe, 0x1490, + 0xbd87, 0xb80d, 0xfe51, 0x380d, 0x5057, 0x380d, 0x5057, 0x380d, 0x5057, + 0x380d, 0x5057, 0x380d, 0x5057, 0x380d, 0x5057, 0x380d, 0x5057, 0x380d, + 0x5057, 0x380d, 0x5057, 0x380d, 0x5057, 0x380d, 0x505f, 0x380d, 0x505f, + 0x380d, 0x505f, 0x380d, 0x505f, 0x380d, 0x505f, 0x380d, 0x505f, 0x380d, + 0x505f, 0x380d, 0x505f, 0x380d, 0x5057, 0x380d, 0x5057, 0x380d, 0x5057, + 0x380d, 0x5057, 0x380d, 0x5057, 0x380d, 0x5057, 0x380d, 0x5057, 0x380d, + 0x5057, 0x3005, 0x5056, 0x1812, 0x4db6, 0x9813, 0x0fff, 0xff40, 0xad06, + 0x0024, 0x4fde, 0x0024, 0xf1fe, 0x1c02, 0xf1fe, 0x0024, 0xf6fe, 0x3786, + 0x3009, 0x2847, 0x35f3, 0x0024, 0x3df4, 0xdbcc, 0x3d01, 0x1bd4, 0x36f3, + 0xd80e, 0x36f1, 0xd80d, 0x36f1, 0x5806, 0x36f0, 0xd804, 0x36f0, 0x5802, + 0x2000, 0x0000, 0x36f2, 0x9813, 0x3613, 0x0024, 0x3e12, 0xb815, 0x0000, + 0x800a, 0x3e10, 0x7802, 0x3e10, 0xf804, 0x3e11, 0x7806, 0x3e11, 0xf813, + 0x3e13, 0xf80e, 0x3e03, 0x7814, 0xf400, 0x4497, 0x6804, 0x044c, 0x0000, + 0x0024, 0x2801, 0xdb18, 0x4094, 0x0024, 0xf224, 0x0024, 0x2401, 0xdac2, + 0x0000, 0x0055, 0x0028, 0x07d3, 0x3114, 0x8024, 0x31f5, 0x0024, 0x3283, + 0x0040, 0x3a80, 0x0040, 0x3a00, 0x0024, 0xbe8a, 0x2412, 0x0020, 0x07d3, + 0xbd87, 0x2849, 0xfe11, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, + 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x501b, 0x2849, 0x501b, 0x2849, + 0x501b, 0x2849, 0x501b, 0x2849, 0x501b, 0x2849, 0x501b, 0x2849, 0x501b, + 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5016, 0x0024, + 0x4db6, 0x0024, 0x0fff, 0xff40, 0xad06, 0x0024, 0x4eda, 0x0024, 0xf7ea, + 0x0024, 0x3f11, 0x4024, 0x3f18, 0x8024, 0x36f3, 0x5814, 0x36f3, 0xd80e, + 0x36f1, 0xd813, 0x36f1, 0x5806, 0x36f0, 0xd804, 0x36f0, 0x5802, 0x2000, + 0x0000, 0x36f2, 0x9815, 0x3613, 0x0024, 0x3e12, 0xb814, 0x0000, 0x800a, + 0x3e10, 0x7802, 0x3e10, 0xf804, 0x3e11, 0x7806, 0x3e11, 0xf813, 0x3e13, + 0xf80e, 0x3e03, 0x4024, 0x6804, 0x044c, 0x0000, 0x0024, 0x2801, 0xf758, + 0x4094, 0x4497, 0xf224, 0x0024, 0x2401, 0xf702, 0x0000, 0x0095, 0x0028, + 0x7fd3, 0xbe8a, 0x0452, 0x31f5, 0x0a0c, 0x3010, 0x0024, 0x3010, 0x4024, + 0x3a80, 0x4024, 0x3a80, 0x0024, 0x3010, 0x0024, 0x3010, 0x4024, 0x3a80, + 0x4024, 0x3a00, 0x3812, 0x0010, 0x41d3, 0xbd87, 0x2849, 0xfe11, 0x2849, + 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, + 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, + 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, + 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, + 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, + 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, + 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2041, 0x3223, + 0x104c, 0x501b, 0x2041, 0x32e3, 0x13cc, 0x3283, 0x120c, 0x501b, 0x2849, + 0x501b, 0x2849, 0x501b, 0x2849, 0x501b, 0x2849, 0x5017, 0x2849, 0x5017, + 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, + 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, + 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, + 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, + 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, + 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, 0x2849, 0x5017, + 0x2849, 0x5016, 0x9812, 0x4db6, 0x2452, 0x0fff, 0xff40, 0xad06, 0x07d4, + 0x4dee, 0x084c, 0x3f11, 0x8024, 0x3f31, 0xc024, 0x36f3, 0x4024, 0x36f3, + 0xd80e, 0x36f1, 0xd813, 0x36f1, 0x5806, 0x36f0, 0xd804, 0x36f0, 0x5802, + 0x2000, 0x0000, 0x36f2, 0x9814, 0x3613, 0x0024, 0x3e12, 0xb815, 0x0000, + 0x800a, 0x3e10, 0x3801, 0x3e10, 0xb803, 0x3e11, 0x780d, 0x6840, 0xb80e, + 0x0000, 0x0024, 0x2801, 0xfe18, 0x4490, 0x380f, 0xf200, 0x0024, 0x003f, + 0xc001, 0x2401, 0xfdc0, 0x0000, 0x0200, 0xb386, 0x0445, 0xb51a, 0x0442, + 0xad06, 0x0024, 0xc356, 0x0024, 0x3810, 0xc024, 0x36f3, 0xd80e, 0x36f1, + 0x580d, 0x36f0, 0x9803, 0x36f0, 0x1801, 0x2000, 0x0000, 0x36f2, 0x9815, + 0x3613, 0x0024, 0x3e12, 0xb815, 0x0000, 0x800a, 0x3e10, 0x3801, 0x3e10, + 0xb805, 0x3e13, 0xf80e, 0x3e03, 0x4024, 0x6840, 0x0024, 0x0000, 0x0024, + 0x2802, 0x0498, 0x4490, 0x0024, 0x0000, 0x0201, 0xf200, 0x0024, 0x2402, + 0x0440, 0x0000, 0x3fc2, 0x3110, 0x0024, 0xa010, 0x0445, 0xb52a, 0x0024, + 0xc050, 0x0024, 0x3810, 0x0024, 0x36f3, 0x4024, 0x36f3, 0xd80e, 0x36f0, + 0x9805, 0x36f0, 0x1801, 0x2000, 0x0000, 0x36f2, 0x9815, 0x3613, 0x0024, + 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3615, 0x0024, 0x3e10, + 0x7810, 0x0003, 0xf410, 0xb882, 0x3811, 0x0002, 0x0611, 0x3009, 0x3812, + 0x0002, 0x0d12, 0x2914, 0xbec0, 0x0000, 0x0700, 0x0003, 0xf410, 0x0000, + 0x4140, 0x3810, 0x0024, 0x0003, 0xf400, 0x3824, 0x4024, 0x0002, 0x70d1, + 0x38f4, 0x9812, 0x3804, 0x4024, 0x36f4, 0x4024, 0x36f0, 0x5810, 0x3405, + 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, + 0x3613, 0x0024, 0x3e22, 0xb815, 0x3e05, 0xb814, 0x3615, 0x0024, 0x3405, + 0x9014, 0x36e3, 0x0024, 0x2000, 0x0000, 0x36f2, 0x9815, 0x0000, 0x0200, + 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3655, + 0x0024, 0x0000, 0x800a, 0x3e10, 0xb804, 0x3e11, 0x7810, 0x3e14, 0x504c, + 0xb880, 0x3840, 0x3e10, 0x0024, 0xf400, 0x4500, 0x3e10, 0x130c, 0x3430, + 0x0024, 0xf400, 0x4010, 0x3e00, 0x004c, 0x3002, 0x0024, 0x2000, 0x0000, + 0x0002, 0x1408, 0x0000, 0x0201, 0x6012, 0x9b4c, 0x3413, 0x0024, 0x2802, + 0x1601, 0xf400, 0x4511, 0x34f3, 0x1bcc, 0x2802, 0x1880, 0xbc82, 0x0024, + 0x2900, 0x5b40, 0x3100, 0x93cc, 0xb182, 0x184c, 0x3113, 0x3840, 0x2900, + 0x5b40, 0x3100, 0x8024, 0x4088, 0x9bc0, 0xf400, 0x4105, 0x0000, 0x0004, + 0xcce2, 0x0024, 0x36f4, 0x4024, 0x36f1, 0x5810, 0x36f0, 0x9804, 0x3405, + 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, + 0x0000, 0x0200, 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, + 0xb814, 0x3655, 0x0024, 0x0000, 0x800a, 0x3e11, 0x3805, 0x3e14, 0x3811, + 0x3e10, 0x104c, 0xb880, 0x0024, 0x3e10, 0x0024, 0xf400, 0x4500, 0x3e10, + 0x130c, 0x3430, 0x0024, 0xf400, 0x4010, 0x3e00, 0x004c, 0x3002, 0x0024, + 0x2000, 0x0000, 0x0002, 0x1f88, 0x0000, 0x0201, 0x6012, 0x9b0c, 0x3443, + 0x0024, 0x2802, 0x2141, 0xf400, 0x4511, 0x2802, 0x2280, 0xbc82, 0x130c, + 0x31f0, 0x130c, 0xb182, 0x0404, 0xf400, 0x4105, 0x0000, 0x0004, 0xcce2, + 0x0024, 0x36f4, 0x1811, 0x36f1, 0x1805, 0x3405, 0x9014, 0x36f3, 0x0024, + 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x0000, 0x0100, 0x3613, + 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3635, 0x0024, + 0x0000, 0x800a, 0x3e10, 0xb804, 0x3e11, 0x7810, 0x3e14, 0x504c, 0xb880, + 0x3840, 0x3e10, 0x0024, 0xf400, 0x4500, 0x3e10, 0x130c, 0x3430, 0x0024, + 0xf400, 0x4010, 0x3e00, 0x004c, 0x3002, 0x0024, 0x2000, 0x0000, 0x0002, + 0x2948, 0x0000, 0x0101, 0x6012, 0x9b4c, 0x3413, 0x0024, 0x2802, 0x2b41, + 0xf400, 0x4511, 0x34f3, 0x1bcc, 0x2802, 0x2dc0, 0xbc82, 0x0024, 0x2900, + 0x5b40, 0x3100, 0x93cc, 0xb182, 0x184c, 0x3113, 0x3840, 0x2900, 0x5b40, + 0x3100, 0x8024, 0x4088, 0x9bc0, 0xf400, 0x4105, 0x0000, 0x0004, 0xcce2, + 0x0024, 0x36f4, 0x4024, 0x36f1, 0x5810, 0x36f0, 0x9804, 0x3405, 0x9014, + 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x0000, + 0x0100, 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, + 0x3635, 0x0024, 0x0000, 0x800a, 0x3e11, 0x3805, 0x3e14, 0x3811, 0x3e10, + 0x104c, 0xb880, 0x0024, 0x3e10, 0x0024, 0xf400, 0x4500, 0x3e10, 0x130c, + 0x3430, 0x0024, 0xf400, 0x4010, 0x3e00, 0x004c, 0x3002, 0x0024, 0x2000, + 0x0000, 0x0002, 0x34c8, 0x0000, 0x0101, 0x6012, 0x9b0c, 0x3423, 0x0024, + 0x2802, 0x3681, 0xf400, 0x4511, 0x2802, 0x37c0, 0xbc82, 0x138c, 0x31f0, + 0x138c, 0xb182, 0x0404, 0xf400, 0x4105, 0x0000, 0x0004, 0xcce2, 0x0024, + 0x36f4, 0x1811, 0x36f1, 0x1805, 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, + 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x0000, 0x0080, 0x3613, 0x0024, + 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3635, 0x0024, 0x0000, + 0x800a, 0x3e14, 0x3811, 0x3e10, 0x104c, 0xb880, 0x0024, 0x3e10, 0x0024, + 0xf400, 0x4500, 0x3e10, 0x130c, 0x3430, 0x0024, 0xf400, 0x4010, 0x3e00, + 0x004c, 0x3002, 0x0024, 0x2000, 0x0000, 0x0002, 0x3e48, 0x0000, 0x0081, + 0x6012, 0x1b0c, 0x0000, 0x0024, 0x2802, 0x4001, 0xb182, 0x104c, 0x2802, + 0x4040, 0xbc82, 0x13cc, 0x34f0, 0x0024, 0x36f4, 0x1811, 0x3405, 0x9014, + 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, + 0x0024, 0x3e22, 0xb815, 0x3e05, 0xb814, 0x3645, 0x0024, 0x0000, 0x800a, + 0x3e10, 0x3801, 0x3e10, 0xb804, 0x3e11, 0x7806, 0x3e11, 0xf810, 0x3e14, + 0x780d, 0x3e03, 0xf80e, 0x0003, 0xffce, 0xb880, 0x108c, 0x3c10, 0x0024, + 0x3ce0, 0x0024, 0x2402, 0x6e0e, 0x3cf0, 0x0024, 0x0006, 0x18d0, 0xbe8a, + 0x104c, 0x6892, 0x13c0, 0xb010, 0x0024, 0x0000, 0x0041, 0x3000, 0x0024, + 0x2802, 0x4885, 0xfe02, 0x0024, 0x2802, 0x48c0, 0x4eba, 0x0024, 0x6eba, + 0x0024, 0x0000, 0x0081, 0x3413, 0x004c, 0x34f0, 0x0024, 0xb010, 0x0024, + 0x0000, 0x0024, 0x2802, 0x4b45, 0x4192, 0x0000, 0xfe02, 0x0024, 0x2802, + 0x4bc0, 0x4eba, 0x0024, 0xfe02, 0x0024, 0x6eba, 0x0024, 0x0000, 0x0101, + 0x3413, 0x004c, 0x34f0, 0x0024, 0xb010, 0x0024, 0x0000, 0x0041, 0x3000, + 0x0024, 0x2802, 0x4e45, 0xfe02, 0x0024, 0x2802, 0x4e80, 0x4eba, 0x0024, + 0x6eba, 0x0024, 0x0000, 0x0201, 0x3413, 0x004c, 0x34f0, 0x0024, 0xb010, + 0x0024, 0x0000, 0x0041, 0x3000, 0x0024, 0x2802, 0x5105, 0xfe02, 0x0024, + 0x2802, 0x5140, 0x4eba, 0x0024, 0x6eba, 0x0024, 0x0000, 0x0401, 0x3413, + 0x004c, 0x34f0, 0x0024, 0xb010, 0x0024, 0x0000, 0x0041, 0x3000, 0x0024, + 0x2802, 0x53c5, 0xfe02, 0x0024, 0x2802, 0x5400, 0x4eba, 0x0024, 0x6eba, + 0x0024, 0x0000, 0x0801, 0x3413, 0x004c, 0x34f0, 0x0024, 0xb010, 0x0024, + 0x0000, 0x0041, 0x3000, 0x0024, 0x2802, 0x5685, 0xfe02, 0x0024, 0x2802, + 0x56c0, 0x4eba, 0x0024, 0x6eba, 0x0024, 0x0000, 0x1001, 0x3413, 0x004c, + 0x34f0, 0x0024, 0xb010, 0x0024, 0x0000, 0x0041, 0x3000, 0x0024, 0x2802, + 0x5945, 0xfe02, 0x0024, 0x2802, 0x5980, 0x4eba, 0x0024, 0x6eba, 0x0024, + 0x0000, 0x2001, 0x3413, 0x004c, 0x34f0, 0x0024, 0xb010, 0x0024, 0x0000, + 0x0041, 0x3000, 0x0024, 0x2802, 0x5c05, 0xfe02, 0x0024, 0x2802, 0x5c40, + 0x4eba, 0x0024, 0x6eba, 0x0024, 0x0000, 0x4001, 0x3413, 0x004c, 0x34f0, + 0x0024, 0xb010, 0x0024, 0x0000, 0x0041, 0x3000, 0x0024, 0x2802, 0x5ec5, + 0xfe02, 0x0024, 0x2802, 0x5f00, 0x4eba, 0x0024, 0x6eba, 0x0024, 0x0000, + 0x8001, 0x3413, 0x004c, 0x34f0, 0x0024, 0xb010, 0x0024, 0x0000, 0x0041, + 0x3000, 0x0024, 0x2802, 0x6185, 0xfe02, 0x0024, 0x2802, 0x61c0, 0x4eba, + 0x0024, 0x6eba, 0x0024, 0x0001, 0x0001, 0x3413, 0x004c, 0x34f0, 0x0024, + 0xb010, 0x0024, 0x0000, 0x0041, 0x3000, 0x0024, 0x2802, 0x6445, 0xfe02, + 0x0024, 0x2802, 0x6480, 0x4eba, 0x0024, 0x6eba, 0x0024, 0x0002, 0x0001, + 0x3413, 0x004c, 0x34f0, 0x0024, 0xb010, 0x0024, 0x0000, 0x0041, 0x3000, + 0x0024, 0x2802, 0x6705, 0xfe02, 0x0024, 0x2802, 0x6740, 0x4eba, 0x0024, + 0x6eba, 0x0024, 0xf1ea, 0x104c, 0x4e82, 0x1042, 0x0008, 0x0001, 0x4122, + 0x0024, 0xf400, 0x4055, 0x0000, 0x0041, 0x3d00, 0x0024, 0x3410, 0x0024, + 0xfe02, 0x0024, 0x48b2, 0x0024, 0x6cee, 0x1380, 0x0000, 0x0041, 0x2802, + 0x6bc9, 0xfe02, 0x4511, 0x3413, 0x0024, 0x3c11, 0x0024, 0x34e0, 0x0024, + 0xfe02, 0x4511, 0x48b2, 0x0024, 0x6cee, 0x1080, 0x0000, 0x0024, 0x2802, + 0x6dd8, 0x0000, 0x0024, 0x3ce1, 0x0024, 0xf400, 0x4511, 0x3420, 0x0024, + 0x6090, 0x934c, 0x3900, 0x0024, 0x36f3, 0xd80e, 0x36f4, 0x580d, 0x36f1, + 0xd810, 0x36f1, 0x5806, 0x36f0, 0x9804, 0x36f0, 0x1801, 0x3405, 0x9014, + 0x36e3, 0x0024, 0x2000, 0x0000, 0x36f2, 0x9815, 0x3613, 0x0024, 0x3e12, + 0xb817, 0x0000, 0x0657, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3685, 0x0024, + 0x0000, 0x800a, 0x3e10, 0x7802, 0x3e10, 0xf804, 0x3e11, 0x7806, 0x3e11, + 0xf810, 0x3e14, 0x7812, 0x3e04, 0xd34c, 0x2902, 0x41c0, 0x6898, 0x10d2, + 0xf400, 0x4490, 0x34c3, 0x010c, 0x34f0, 0x184c, 0x3800, 0x0024, 0x3460, + 0x0024, 0x4080, 0x0024, 0x0000, 0x0100, 0x2802, 0x7805, 0x0000, 0x0024, + 0x0006, 0x0580, 0x3009, 0x128c, 0x3464, 0x4024, 0x3900, 0x0024, 0x0000, + 0x0100, 0xb880, 0x3840, 0x3e10, 0x0024, 0xf400, 0x4500, 0x3e10, 0x12cc, + 0x3440, 0x0024, 0xf400, 0x4011, 0x3e00, 0x044c, 0x3102, 0x0024, 0x2000, + 0x0000, 0x0002, 0x7a88, 0x0000, 0x0101, 0x6012, 0x9b0c, 0x0012, 0x5101, + 0x2802, 0x7c41, 0x3413, 0x0024, 0x2803, 0xd9c0, 0x4480, 0x13cc, 0xf400, + 0x4510, 0x34f0, 0x004c, 0x6012, 0x0000, 0x003f, 0xc001, 0x2802, 0x9515, + 0xb010, 0x0024, 0x000c, 0xc001, 0x6012, 0x0024, 0x0000, 0x0024, 0x2802, + 0x9515, 0x0000, 0x0024, 0xb880, 0x110c, 0x3cd0, 0x184c, 0x0000, 0x0080, + 0xb880, 0x3840, 0x3e10, 0x0024, 0xf400, 0x4500, 0x3e10, 0x12cc, 0x3440, + 0x0024, 0x3e00, 0x0024, 0x3102, 0x0024, 0x2000, 0x0000, 0x0002, 0x8208, + 0x0000, 0x0100, 0x36d3, 0x104c, 0xb880, 0x3840, 0x3e10, 0x0024, 0xf400, + 0x4500, 0x3e10, 0x12cc, 0x3440, 0x0024, 0x3e00, 0x0024, 0x3102, 0x0024, + 0x2000, 0x0000, 0x0002, 0x84c8, 0x001f, 0xc001, 0x0000, 0x1fc2, 0x3123, + 0x108c, 0xf400, 0x4510, 0x34e0, 0x1b0c, 0xb010, 0x0081, 0xf200, 0x0024, + 0xb122, 0x0024, 0x4010, 0x0024, 0x3800, 0x0024, 0x31f0, 0x0024, 0x4080, + 0x0024, 0x3100, 0x0024, 0x2802, 0x8c85, 0x4080, 0x0024, 0x0000, 0x0043, + 0x34c3, 0x184c, 0x6890, 0x844c, 0x3e10, 0x0024, 0x3000, 0x8024, 0xfe26, + 0x0024, 0x48b6, 0x0024, 0x3e10, 0x8024, 0x3e10, 0xc024, 0x3440, 0x0024, + 0x3e00, 0x0024, 0x3102, 0x0024, 0x2000, 0x0000, 0x0002, 0x8c08, 0x2802, + 0x9040, 0x36c3, 0x0024, 0x0000, 0x0024, 0x2802, 0x9045, 0x0000, 0x0024, + 0x0000, 0x0041, 0x3000, 0x184c, 0xfe02, 0x930c, 0x48b2, 0x0024, 0x3e10, + 0x0024, 0x3e10, 0x4024, 0x3440, 0xc024, 0x3e00, 0xc024, 0x3102, 0x0024, + 0x2000, 0x0000, 0x0002, 0x9008, 0x36d3, 0x0024, 0x0000, 0x0100, 0x3613, + 0x104c, 0xb880, 0x3840, 0x3e10, 0x0024, 0xf400, 0x4500, 0x3e10, 0x12cc, + 0x3440, 0x0024, 0xf400, 0x4011, 0x3e00, 0x044c, 0x3102, 0x0024, 0x2000, + 0x0000, 0x0002, 0x9348, 0x0000, 0x0101, 0x6012, 0x1b0c, 0x0000, 0x0024, + 0x2802, 0x9501, 0x0000, 0x0024, 0x2803, 0xd9c0, 0x4480, 0x0024, 0x0011, + 0x9481, 0x3413, 0x0024, 0xf400, 0x4510, 0x34f0, 0x004c, 0x6012, 0x0000, + 0x0013, 0x4e01, 0x2803, 0x1fd5, 0x6012, 0x0024, 0x0000, 0x0024, 0x2803, + 0x1fd5, 0x0000, 0x0024, 0x34c3, 0x184c, 0x3470, 0x8024, 0x2902, 0x1a80, + 0x3e00, 0x8024, 0x3c10, 0x0024, 0x0000, 0x0100, 0x3cd0, 0x4024, 0xb880, + 0x3840, 0x3e10, 0x0024, 0xf400, 0x4500, 0x3e10, 0x13cc, 0x3e00, 0x8024, + 0x3102, 0x0024, 0x2000, 0x0000, 0x0002, 0x9b88, 0x0000, 0x0101, 0x6012, + 0x9b0c, 0x0011, 0x14c1, 0x2802, 0x9d41, 0x3413, 0x0024, 0x2803, 0xd9c0, + 0x4480, 0x13cc, 0xf400, 0x4510, 0x34f0, 0x004c, 0x6012, 0x0000, 0x0011, + 0x0801, 0x2803, 0x1fd5, 0x6012, 0x0024, 0x0000, 0x0024, 0x2803, 0x1fd5, + 0x0000, 0x0024, 0xb880, 0x11cc, 0xb882, 0x3040, 0x002b, 0x1100, 0xb888, + 0x3040, 0x3c90, 0x4024, 0x3493, 0x0024, 0x3450, 0x0024, 0x4080, 0x0024, + 0x0006, 0x0a40, 0x2803, 0x1b45, 0x0000, 0x0024, 0x34b3, 0x0024, 0x3454, + 0x0024, 0x2803, 0x1b40, 0x3800, 0x0024, 0xb880, 0x3840, 0x3e10, 0x0024, + 0xf400, 0x4500, 0x3e10, 0x12cc, 0x3440, 0x0024, 0xf400, 0x4010, 0x3e00, + 0x004c, 0x3002, 0x0024, 0x2000, 0x0000, 0x0002, 0xa5c8, 0x0000, 0x0101, + 0x6012, 0x130c, 0x3440, 0x9b4c, 0x2802, 0xa781, 0xf400, 0x4100, 0x2803, + 0xd9c0, 0x3009, 0x1bcc, 0x2902, 0x1a80, 0x3e00, 0x8024, 0x36f3, 0x114c, + 0x3c10, 0x0024, 0x3cb0, 0x4024, 0xf400, 0x4511, 0x0014, 0x1481, 0x34f0, + 0x0024, 0x6012, 0x0024, 0x0013, 0xd401, 0x2803, 0x1715, 0x0000, 0x0024, + 0x3113, 0x0024, 0x3100, 0x0024, 0x6012, 0x0024, 0x0000, 0x0024, 0x2803, + 0x1715, 0x0000, 0x0024, 0x3613, 0x0024, 0x2902, 0x2440, 0x3e00, 0x8024, + 0x36f3, 0x11cc, 0x3433, 0x0024, 0x3c10, 0x0024, 0x3c90, 0x4024, 0x2803, + 0x1000, 0x34c3, 0x0024, 0xb880, 0x3840, 0x3e10, 0x0024, 0xf400, 0x4500, + 0x3e10, 0x12cc, 0x3440, 0x0024, 0xf400, 0x4010, 0x3e00, 0x004c, 0x3002, + 0x0024, 0x2000, 0x0000, 0x0002, 0xb0c8, 0x0000, 0x0101, 0x6012, 0x130c, + 0x3440, 0x9b4c, 0x2802, 0xb281, 0xf400, 0x4100, 0x2803, 0xd9c0, 0x3009, + 0x1bcc, 0x2902, 0x1a80, 0x3e00, 0x8024, 0x36f3, 0x11cc, 0x3453, 0x0024, + 0x3c10, 0x0024, 0x0000, 0x0300, 0xb882, 0x33c1, 0x3411, 0x8024, 0x3491, + 0xc024, 0x6cf2, 0x13cc, 0xf400, 0x4511, 0x3110, 0x92cc, 0x31f0, 0xc024, + 0x6dc2, 0x0024, 0x3910, 0x0024, 0x39b0, 0x4024, 0x0011, 0x94c1, 0x3110, + 0x0024, 0x6012, 0x0400, 0x0008, 0x0801, 0x2802, 0xbd95, 0x6012, 0x0024, + 0x0000, 0x0024, 0x2802, 0xbd95, 0x0000, 0x0024, 0x34c3, 0x184c, 0x3440, + 0x8024, 0x2902, 0x2fc0, 0x3e00, 0x8024, 0x0000, 0x0102, 0x36f3, 0x11cc, + 0xb886, 0x104c, 0x3c10, 0x0024, 0x3c90, 0x4024, 0x34e3, 0x0024, 0xf400, + 0x4511, 0x3173, 0x0024, 0x3153, 0x0024, 0x3110, 0x0024, 0x31f0, 0x4024, + 0x6cd6, 0x0024, 0x3910, 0x8024, 0x2803, 0x0b80, 0x39f0, 0xc024, 0x0010, + 0xd201, 0x3413, 0x0024, 0xf400, 0x4511, 0x34f0, 0x044c, 0x6012, 0x0400, + 0x0013, 0x9301, 0x2802, 0xc455, 0x6012, 0x0024, 0x0000, 0x0024, 0x2802, + 0xc455, 0x0000, 0x0024, 0x34c3, 0x184c, 0x3440, 0x8024, 0x2902, 0x3980, + 0x3e00, 0x8024, 0x36f3, 0x11cc, 0xb882, 0x3240, 0xf400, 0x4511, 0x0000, + 0x0080, 0x3173, 0x0024, 0x3153, 0x0024, 0x3110, 0x8024, 0x31f0, 0xc024, + 0x6dc2, 0x0024, 0x3910, 0x0024, 0x2803, 0x0b80, 0x39f0, 0x4024, 0x0011, + 0x14c1, 0x3413, 0x0024, 0xf400, 0x4511, 0x34f0, 0x0024, 0x6012, 0x0024, + 0x0011, 0x0801, 0x2803, 0x0b95, 0x0000, 0x0024, 0x3113, 0x0024, 0x3100, + 0x0024, 0x6012, 0x0024, 0x0000, 0x0024, 0x2803, 0x0b95, 0x0000, 0x0024, + 0x003f, 0xfe82, 0x0000, 0x04d1, 0x3473, 0x020c, 0x3413, 0x04cc, 0x3410, + 0x0024, 0x34e0, 0x4024, 0xac22, 0x0024, 0x3810, 0x0024, 0x38f0, 0x4024, + 0x0000, 0x0081, 0x3490, 0x0024, 0x34c3, 0x0024, 0x3474, 0x0024, 0x3083, + 0x110c, 0x3800, 0x0024, 0x3490, 0x0024, 0x6012, 0x130c, 0x3444, 0x0024, + 0x2802, 0xcf85, 0x3043, 0x0024, 0x34b3, 0x0024, 0x3450, 0x0024, 0x4080, + 0x0024, 0x0000, 0x0184, 0x2802, 0xcf05, 0x0006, 0x0b00, 0x34b3, 0x0024, + 0x3454, 0x0024, 0x3800, 0x0024, 0x2803, 0xd9c0, 0x4480, 0x0024, 0x30f0, + 0x0024, 0x4080, 0x0024, 0x3000, 0x0024, 0x2803, 0x01c5, 0x4080, 0x0024, + 0x0000, 0x0024, 0x2803, 0x01c5, 0x0000, 0x0024, 0x34c3, 0x184c, 0x3440, + 0x8024, 0xf400, 0x4090, 0x3e00, 0x810c, 0x3002, 0x0024, 0x2000, 0x0000, + 0x0002, 0xd348, 0xf400, 0x4491, 0x0000, 0x0610, 0x3473, 0x060c, 0x3910, + 0x114c, 0x3910, 0x5bcc, 0x3410, 0x0024, 0x3490, 0x4024, 0x3910, 0x128c, + 0x2803, 0x01c0, 0x39f0, 0x4024, 0x3053, 0x0024, 0x3090, 0x0024, 0x6012, + 0x038c, 0x3000, 0x0024, 0x2802, 0xecc5, 0x4080, 0x0024, 0x0000, 0x0024, + 0x2802, 0xecc5, 0x0000, 0x0024, 0x34c3, 0x184c, 0x3444, 0x0024, 0x3073, + 0x0024, 0x3053, 0x0024, 0x3070, 0x0024, 0x4080, 0x00cc, 0x0000, 0x0024, + 0x2802, 0xe095, 0x0000, 0x0024, 0x0000, 0x0610, 0xb880, 0x4491, 0x3e10, + 0x060c, 0x3110, 0x930c, 0x31f0, 0xc024, 0x3e10, 0x8024, 0x3e10, 0xc024, + 0x3440, 0x0024, 0xf400, 0x4010, 0x3e00, 0x00cc, 0x3002, 0x0024, 0x2000, + 0x0000, 0x0002, 0xdd88, 0x3473, 0x048c, 0x3110, 0x114c, 0x31f0, 0x41cc, + 0x0000, 0x0411, 0x3c10, 0x010c, 0x3c90, 0x5b0c, 0xbc82, 0x124c, 0x3810, + 0x134c, 0x38f0, 0x4024, 0x3444, 0x0024, 0x2802, 0xeb00, 0x3083, 0x0024, + 0xb78e, 0x4511, 0x3090, 0x3804, 0x30d3, 0x130c, 0x3021, 0x8024, 0x3010, + 0x8024, 0x3050, 0xc024, 0x6fde, 0x0042, 0xfeae, 0x03c3, 0x0000, 0x03d0, + 0x3e00, 0xc60c, 0x48ba, 0x0024, 0xffe6, 0x0024, 0x5daa, 0x0024, 0x0000, + 0x00c2, 0x44be, 0x9804, 0xaf2e, 0x0024, 0xfff0, 0x4007, 0x48b2, 0x0024, + 0xffee, 0x0024, 0x40b2, 0x0024, 0x6890, 0x2440, 0x39f0, 0x4024, 0x3e10, + 0x0024, 0x3110, 0x8024, 0x31f0, 0xc024, 0x3e10, 0x8024, 0x3e10, 0xc024, + 0x3440, 0x0024, 0xf400, 0x4010, 0x3e00, 0x00cc, 0x3002, 0x0024, 0x2000, + 0x0000, 0x0002, 0xe8c8, 0xf400, 0x4513, 0x3073, 0x0dcc, 0x3353, 0x008c, + 0x3310, 0x1b0c, 0x33f0, 0x4024, 0x6cd6, 0x0024, 0xb182, 0x2c42, 0x3bf0, + 0xc024, 0x3020, 0x0024, 0x3810, 0x130c, 0x003f, 0xffc0, 0x38f0, 0x4024, + 0x3444, 0x0024, 0x3073, 0x0024, 0x3053, 0x0024, 0x3800, 0x0024, 0x0004, + 0x0000, 0x3613, 0x130c, 0xb880, 0x3840, 0x3e10, 0x0024, 0x000d, 0x0000, + 0x3e10, 0x0024, 0x3440, 0x0024, 0xf400, 0x4010, 0x3e00, 0x004c, 0x3002, + 0x0024, 0x2000, 0x0000, 0x0002, 0xefc8, 0x0004, 0x0001, 0x6012, 0x1b0c, + 0x0004, 0x0000, 0x2803, 0x0b91, 0x0004, 0x0010, 0xb882, 0x4511, 0x3173, + 0x184c, 0x3153, 0x3804, 0x3110, 0x8024, 0x31f0, 0xc024, 0x6dc2, 0x0024, + 0x3910, 0x0024, 0x39f0, 0x4024, 0x000d, 0x0011, 0x2901, 0xf940, 0x0002, + 0x0004, 0x0005, 0x0010, 0x000d, 0x0011, 0x0000, 0x4001, 0x2901, 0xff80, + 0x0002, 0x0004, 0x0004, 0x0010, 0x0001, 0x0000, 0x0006, 0x8091, 0x3009, + 0x1804, 0x3009, 0x3812, 0x2901, 0xb6c0, 0x0008, 0x0012, 0x0001, 0x0000, + 0x0006, 0x8311, 0x0008, 0x0010, 0x2901, 0xce80, 0x000d, 0x0012, 0x0000, + 0x8000, 0x000d, 0x0010, 0x0006, 0x8591, 0x2901, 0xdd00, 0x0002, 0x0012, + 0x0005, 0x0010, 0x0001, 0x0000, 0x0006, 0x81d1, 0x2901, 0xb6c0, 0x0008, + 0x0012, 0x0001, 0x0000, 0x0006, 0x8451, 0x0008, 0x0010, 0x2901, 0xce80, + 0x000d, 0x0012, 0x0000, 0x8000, 0x000d, 0x0010, 0x0006, 0x86d1, 0x2901, + 0xdd00, 0x0002, 0x0092, 0x0006, 0x8010, 0x3000, 0x9812, 0x6122, 0x930c, + 0x6810, 0x0024, 0x3e10, 0x0024, 0x0002, 0x0000, 0x4020, 0x0024, 0x4020, + 0x0024, 0x4020, 0x0024, 0x4020, 0x0024, 0x3e10, 0x0024, 0x3440, 0x0024, + 0xf400, 0x4011, 0x3e00, 0x054c, 0x3102, 0x0024, 0x2000, 0x0000, 0x0003, + 0x0148, 0xb880, 0x9b4c, 0x3800, 0x0024, 0x0004, 0x0000, 0xb882, 0x11cc, + 0x3453, 0x0024, 0x3410, 0x8024, 0x3490, 0xc024, 0x6dc2, 0x128c, 0x0000, + 0x0024, 0x2803, 0x0b88, 0x0000, 0x0024, 0x34c3, 0x0024, 0x3404, 0x0024, + 0x3073, 0x0024, 0x3063, 0x0024, 0x3000, 0x0024, 0x4080, 0x1110, 0x003f, + 0xffc1, 0x2802, 0xd5c5, 0x3073, 0x0024, 0x2803, 0x0b80, 0x0000, 0x0024, + 0x3e10, 0x104c, 0xb880, 0x0024, 0x3e10, 0x0024, 0xf400, 0x4500, 0x3e10, + 0x12cc, 0x3440, 0x0024, 0xf400, 0x4010, 0x3e00, 0x004c, 0x3002, 0x0024, + 0x2000, 0x0000, 0x0003, 0x0988, 0xf400, 0x4511, 0x36c3, 0x05cc, 0x3153, + 0x0024, 0x3110, 0x8024, 0x31f0, 0xc024, 0x4d96, 0x0024, 0x3910, 0x8024, + 0x39f0, 0xc024, 0x3473, 0x0024, 0x3453, 0x0024, 0x3410, 0x0024, 0x3490, + 0x4024, 0x4c82, 0x128c, 0x0000, 0x0024, 0x2803, 0x1009, 0x0000, 0x0024, + 0x34c3, 0x184c, 0x3444, 0x0024, 0x3073, 0x0024, 0x3063, 0x0024, 0x3000, + 0x0024, 0x4080, 0x0024, 0x0000, 0x0040, 0x2803, 0x06c5, 0x0000, 0x0024, + 0x36f3, 0x0024, 0x0000, 0x0300, 0xb882, 0x114c, 0x3410, 0x984c, 0x34b0, + 0xc024, 0x6dc2, 0x0024, 0x0000, 0x0100, 0x2802, 0xae58, 0x0000, 0x0024, + 0x2803, 0x1700, 0x36f3, 0x13cc, 0x3e10, 0x104c, 0xb880, 0x0024, 0x3e10, + 0x0024, 0xf400, 0x4500, 0x3e10, 0x12cc, 0x3440, 0x0024, 0xf400, 0x4010, + 0x3e00, 0x004c, 0x3002, 0x0024, 0x2000, 0x0000, 0x0003, 0x1548, 0x36c3, + 0x114c, 0xf400, 0x4511, 0x3110, 0x92cc, 0x31f0, 0xc024, 0x4d96, 0x0024, + 0x3910, 0x8024, 0x39f0, 0xc024, 0x3453, 0x0024, 0x3410, 0x0024, 0x34a0, + 0x4024, 0x4c82, 0x0024, 0x0000, 0x0024, 0x2803, 0x1b45, 0x0000, 0x0024, + 0x34c3, 0x184c, 0x3444, 0x0024, 0x3073, 0x0024, 0x3063, 0x0024, 0x3000, + 0x0024, 0x4080, 0x0024, 0x0000, 0x0040, 0x2803, 0x1285, 0x0000, 0x0024, + 0x36f3, 0x0024, 0x3433, 0x0024, 0x3410, 0x8024, 0x3490, 0xc024, 0x4d86, + 0x13cc, 0x0000, 0x0024, 0x2803, 0x1f45, 0x0000, 0x0024, 0x3454, 0x184c, + 0x3073, 0x0024, 0x3063, 0x0024, 0x3000, 0x0024, 0x4080, 0x0024, 0x0000, + 0x0100, 0x2802, 0xa345, 0x0000, 0x0024, 0x36f3, 0x12cc, 0x2803, 0xd9c0, + 0x4480, 0x110c, 0x0011, 0x14c1, 0x3413, 0x0024, 0xf400, 0x4510, 0x34f0, + 0x004c, 0x6012, 0x0000, 0x0011, 0x0801, 0x2803, 0xd3d5, 0x6012, 0x0024, + 0x0000, 0x0024, 0x2803, 0xd3d5, 0x0000, 0x0024, 0xb888, 0x12cc, 0x3410, + 0x184c, 0x4080, 0x13c2, 0x0006, 0x0a40, 0x2803, 0x2485, 0x3414, 0x0024, + 0x3800, 0x0024, 0x3400, 0x8024, 0x2902, 0x0f00, 0x3e00, 0x91cc, 0x3c10, + 0x0024, 0x3cc0, 0x4024, 0x2902, 0x0f00, 0x3e00, 0x8024, 0x2902, 0x0f00, + 0x3e00, 0x8024, 0x0000, 0x0702, 0x36f3, 0x10cc, 0xb886, 0x4510, 0x3010, + 0x134c, 0x30f0, 0x494c, 0x6cd6, 0x0024, 0x3810, 0x8024, 0x38f0, 0xc024, + 0x0019, 0x9b41, 0x32b3, 0x104c, 0xf400, 0x4510, 0x34f0, 0x004c, 0x6012, + 0x0000, 0x001d, 0x0801, 0x2803, 0x42d5, 0x6012, 0x0024, 0x0000, 0x0024, + 0x2803, 0x42d5, 0x0000, 0x0024, 0x0000, 0x0511, 0x34c3, 0x184c, 0x3470, + 0x8024, 0x2902, 0x0f00, 0x3e00, 0x8024, 0x3c10, 0x0024, 0x3cc0, 0x4024, + 0x2902, 0x2440, 0x3e00, 0x8024, 0x2902, 0x2440, 0x3e00, 0x91cc, 0x3c10, + 0x0024, 0x3c10, 0x4024, 0x2902, 0x2440, 0x3e00, 0x8024, 0x3c10, 0x0024, + 0x3c10, 0x4024, 0x2902, 0x2440, 0x3e00, 0x8024, 0x3c10, 0x0024, 0x3c90, + 0x4024, 0x2902, 0x2440, 0x3e00, 0x92cc, 0x003f, 0xfe82, 0x3009, 0x11cc, + 0x3463, 0x0024, 0x3c10, 0x0024, 0x3cf0, 0x4024, 0x3410, 0x0024, 0x3490, + 0x4024, 0x3493, 0x0024, 0xac22, 0x130c, 0x3474, 0x0024, 0x3083, 0x11cc, + 0x3810, 0x104c, 0x38f0, 0x448c, 0x3490, 0x0024, 0x3493, 0x0024, 0x34f3, + 0x0024, 0x3404, 0x0024, 0x3083, 0x0024, 0x3800, 0x0024, 0x3440, 0x8024, + 0x2902, 0x2440, 0x3e00, 0x8024, 0xf400, 0x4510, 0x0000, 0x03d1, 0x3009, + 0x020c, 0x3810, 0x0024, 0x3830, 0x4024, 0x2902, 0x0f00, 0x3e00, 0x8024, + 0x3810, 0x0024, 0x38f0, 0x4024, 0x2902, 0x2440, 0x3e00, 0x8024, 0x36f3, + 0x038c, 0x3810, 0x0024, 0x38d0, 0x4024, 0x3010, 0x0024, 0x30b0, 0x4024, + 0x4c92, 0x0024, 0x0000, 0x0080, 0x2803, 0x3c85, 0xb882, 0x0024, 0x6890, + 0x4491, 0xb882, 0x054c, 0x3900, 0x0024, 0x0000, 0x0080, 0x3010, 0x90cc, + 0x30f0, 0xc024, 0x6dc2, 0x0024, 0x0000, 0x0c00, 0x2803, 0x4105, 0xb882, + 0x0024, 0x3493, 0x0024, 0x34f3, 0x0024, 0x3450, 0x0024, 0x4080, 0x0024, + 0x0000, 0x0184, 0x2803, 0x4085, 0x0006, 0x0b00, 0x34b3, 0x0024, 0x3454, + 0x4024, 0x3900, 0x0024, 0x2803, 0xd9c0, 0x4480, 0x0024, 0xf400, 0x4511, + 0x3110, 0x934c, 0x31f0, 0xc024, 0x6dc2, 0x0024, 0x3910, 0x0024, 0x2803, + 0xc740, 0x39f0, 0x4024, 0x0019, 0x1841, 0x3413, 0x0024, 0xf400, 0x4510, + 0x34f0, 0x004c, 0x6012, 0x0000, 0x001d, 0x1841, 0x2803, 0xc755, 0x6012, + 0x0024, 0x0000, 0x0024, 0x2803, 0xc755, 0x0000, 0x0024, 0x34c3, 0x184c, + 0x3440, 0x8024, 0x2902, 0x0f00, 0x3e00, 0x8024, 0x0000, 0x0302, 0x36f3, + 0x10cc, 0xb886, 0x3040, 0x3cf0, 0x4024, 0xf400, 0x4510, 0x3010, 0x134c, + 0x30f0, 0x4024, 0x6cd6, 0x0024, 0x3810, 0x8024, 0x3890, 0xc024, 0x30f3, + 0x0024, 0x3004, 0x4024, 0x3143, 0x0024, 0x3100, 0x0024, 0x4080, 0x0024, + 0x0000, 0x0024, 0x2803, 0xbbc5, 0x0000, 0x0024, 0x31f3, 0x0024, 0x3100, + 0x0024, 0x4080, 0x0024, 0x0000, 0x0024, 0x2803, 0xbbc5, 0x0000, 0x0024, + 0x3000, 0x984c, 0xf400, 0x4091, 0x3e00, 0x850c, 0x3102, 0x0024, 0x2000, + 0x0000, 0x0003, 0x4e08, 0xf400, 0x4493, 0x3073, 0x3812, 0x0000, 0x0612, + 0x3383, 0x1bd2, 0x3b10, 0x0024, 0x3b10, 0x4024, 0x3010, 0x0024, 0x30f0, + 0x4024, 0x3b10, 0x0024, 0x2803, 0xbbc0, 0x3bf0, 0x4024, 0x3483, 0x0024, + 0x1fff, 0xfb95, 0x3410, 0x0024, 0x3480, 0x4024, 0xf1c2, 0x4510, 0x003f, + 0xffc1, 0x3083, 0x130c, 0x3800, 0x0024, 0x3444, 0x4024, 0x3173, 0x0024, + 0x3153, 0x0024, 0x3190, 0x0024, 0x6012, 0x078c, 0x3100, 0x0024, 0x2803, + 0x8d05, 0x4080, 0x0024, 0x0000, 0x0024, 0x2803, 0x8d05, 0x0000, 0x0024, + 0x34c3, 0x0024, 0x3444, 0x4024, 0x3173, 0x0024, 0x3153, 0x0024, 0x3100, + 0x0024, 0x4080, 0x0024, 0x0000, 0x0024, 0x2803, 0x6095, 0x0000, 0x0024, + 0xb880, 0x4493, 0x3613, 0x130c, 0x3e20, 0x0024, 0x3009, 0x3812, 0x0000, + 0x0612, 0x3383, 0x1bd2, 0x3310, 0x8024, 0x33f0, 0xc024, 0x3e10, 0x8024, + 0x3e10, 0xc024, 0x3440, 0x0024, 0xf400, 0x4010, 0x3e00, 0x00cc, 0x3002, + 0x0024, 0x2000, 0x0000, 0x0003, 0x5bc8, 0xf400, 0x4490, 0x0000, 0x0691, + 0x3433, 0x020c, 0x3010, 0x1b0c, 0x30f0, 0x4024, 0x0000, 0x0410, 0x3c10, + 0x0024, 0xbc82, 0x3241, 0x34f3, 0x0024, 0x3404, 0x4024, 0x3183, 0x0024, + 0x3910, 0x0024, 0x39f0, 0x4024, 0x3444, 0x0024, 0x3073, 0x0024, 0x3073, + 0x0024, 0x3810, 0x0024, 0x2803, 0x8b80, 0x38f0, 0x4024, 0xb182, 0x048c, + 0x3111, 0x804c, 0x3151, 0xd84c, 0x6cf2, 0x0442, 0x3110, 0xd30c, 0xfea2, + 0x0024, 0x48be, 0x0024, 0xff86, 0x0024, 0x51ae, 0x0024, 0x003f, 0xfdc2, + 0x46b2, 0x0024, 0x0000, 0x0020, 0xac22, 0x0024, 0x0000, 0x0302, 0xac22, + 0x0024, 0x6890, 0x2040, 0x38f0, 0x4024, 0x3e10, 0x0024, 0x3100, 0x8024, + 0x3011, 0x8024, 0x30f1, 0xc024, 0xff74, 0x4087, 0x48b6, 0x0024, 0xffee, + 0x0024, 0x42b6, 0x0024, 0x3e10, 0x8024, 0x3e10, 0xc024, 0x3440, 0x0024, + 0xf400, 0x4013, 0x3e00, 0x0ccc, 0x3302, 0x0024, 0x2000, 0x0000, 0x0003, + 0x68c8, 0x0000, 0x05d5, 0x3100, 0x10cc, 0x0000, 0x05d1, 0x3011, 0x9b0c, + 0x30f1, 0xc024, 0xff70, 0x4007, 0x48b2, 0x4510, 0xffee, 0x934c, 0x40b2, + 0x0042, 0x30f0, 0xd20c, 0x1fff, 0xfa15, 0x4dc2, 0x0024, 0x003f, 0xff42, + 0x3810, 0x0024, 0x38f0, 0x4024, 0x3410, 0x0024, 0x3480, 0x4024, 0xac22, + 0x4510, 0x3083, 0x130c, 0x3810, 0x0024, 0x4c82, 0x23c1, 0x0000, 0x0510, + 0x2803, 0x7658, 0x4c86, 0x1111, 0x68c6, 0x060c, 0x3110, 0x0024, 0x2914, + 0xa580, 0x31f0, 0x4024, 0x0000, 0x0411, 0x0000, 0x05d5, 0x4d82, 0x130c, + 0x3444, 0x0024, 0x3083, 0x120c, 0x1fff, 0xfa15, 0x3010, 0x850c, 0x30f0, + 0xc024, 0x6dc2, 0x0024, 0x3810, 0x0024, 0x38f0, 0x4024, 0x3411, 0x8024, + 0x3481, 0xc024, 0x68f6, 0x130c, 0x3404, 0x0024, 0x3083, 0x0024, 0x3010, + 0x0024, 0x2914, 0xa580, 0x30f0, 0x4024, 0x3444, 0x0024, 0x3073, 0x0024, + 0x3073, 0x0024, 0x3010, 0x8024, 0x30f0, 0xc024, 0x2803, 0x7d80, 0x6dc2, + 0x0024, 0x3183, 0x0024, 0x3110, 0x0024, 0x2914, 0xa580, 0x31f0, 0x4024, + 0x0000, 0x0411, 0x0000, 0x05d5, 0x4d82, 0x130c, 0x3444, 0x0024, 0x3083, + 0x120c, 0x1fff, 0xfa15, 0x3010, 0x850c, 0x30f0, 0xc024, 0x4dc2, 0x0024, + 0x3810, 0x0024, 0x38f0, 0x4024, 0x3410, 0x8024, 0x3480, 0xc024, 0x34c3, + 0x0024, 0x3404, 0x0024, 0x3083, 0x0024, 0x3010, 0x0024, 0x2914, 0xa580, + 0x30f0, 0x4024, 0x3444, 0x0024, 0x3073, 0x0024, 0x3073, 0x0024, 0x3010, + 0x8024, 0x30f0, 0xc024, 0x4dc2, 0x0024, 0x0000, 0x0411, 0x3810, 0x130c, + 0x38f0, 0x4024, 0x3404, 0x0024, 0x3083, 0x0024, 0x3010, 0x0024, 0x30f0, + 0x4024, 0x4c82, 0x0024, 0x0000, 0x0024, 0x2803, 0x8518, 0x0000, 0x0024, + 0x3404, 0x410c, 0x3010, 0x0024, 0x30f0, 0x4024, 0x0000, 0x0410, 0x3183, + 0x0024, 0x3111, 0x8024, 0x31f1, 0xc024, 0x4fc2, 0x0024, 0x3910, 0x0024, + 0x39f0, 0x4024, 0x0000, 0x0411, 0x3404, 0x0024, 0x3073, 0x0024, 0x3073, + 0x0024, 0x3010, 0x8024, 0x30f0, 0xc024, 0x4d96, 0x0024, 0x3810, 0x8024, + 0x38f0, 0xc024, 0x3444, 0x0024, 0x3083, 0x0024, 0x3010, 0x0024, 0x3030, + 0x4024, 0x3010, 0x8024, 0x30f0, 0xc024, 0x6cde, 0x0024, 0x0000, 0x0410, + 0x2803, 0x8b91, 0x0000, 0x0024, 0x34c3, 0x0024, 0x3404, 0x4024, 0x3183, + 0x0024, 0x3111, 0x8024, 0x31f1, 0xc024, 0x6fd6, 0x0024, 0x3910, 0x8024, + 0x39f0, 0xc024, 0x3444, 0x0024, 0x3073, 0x0024, 0x3073, 0x0024, 0x3010, + 0x0024, 0x30f0, 0x4024, 0x6c92, 0x0024, 0x3810, 0x0024, 0x38f0, 0x4024, + 0x003f, 0xffc0, 0x34c3, 0x0024, 0x3444, 0x0024, 0x3073, 0x0024, 0x3053, + 0x0024, 0x3800, 0x0024, 0x0000, 0x0551, 0xb880, 0x4510, 0x2803, 0xb040, + 0x3083, 0x0024, 0x0000, 0x0455, 0x3483, 0x184c, 0x1fff, 0xfb95, 0xb880, + 0x1046, 0x3481, 0xc024, 0x3e11, 0x930c, 0x3e10, 0x0024, 0x0004, 0x0000, + 0x3e10, 0x0024, 0x3440, 0x0024, 0xf400, 0x4010, 0x3e00, 0x004c, 0x3002, + 0x0024, 0x2000, 0x0000, 0x0003, 0x91c8, 0xb182, 0x1b0c, 0x6cf6, 0x0024, + 0x0000, 0x0555, 0x2803, 0xc208, 0x0000, 0x0024, 0x3433, 0x0024, 0xf400, + 0x4511, 0x3110, 0x934c, 0x31f0, 0xd20c, 0x1fff, 0xfad5, 0x6dfe, 0x0024, + 0x3911, 0x8024, 0x39f1, 0xc024, 0x3480, 0x0024, 0x4080, 0x0024, 0x0000, + 0x0455, 0x2803, 0xa115, 0x0000, 0x0024, 0x3483, 0x184c, 0x1fff, 0xfb95, + 0x3410, 0x3804, 0x3480, 0x4024, 0x3473, 0x0024, 0x3443, 0x0024, 0x3410, + 0x8024, 0xfea2, 0x1243, 0x48ba, 0x3803, 0xfe86, 0x92cc, 0x51aa, 0x0024, + 0x44b2, 0x9bc4, 0x6fc6, 0x0024, 0x0000, 0x0595, 0x2803, 0xa118, 0x0000, + 0x0024, 0x3483, 0x0024, 0x1fff, 0xfa95, 0x3480, 0x0024, 0x4080, 0x0024, + 0x0005, 0xffd1, 0x2803, 0xa105, 0x3100, 0x0024, 0x4080, 0x4510, 0x0000, + 0x0595, 0x2803, 0xa115, 0x0000, 0x0024, 0x3613, 0x120c, 0x1fff, 0xfa95, + 0x3009, 0x3811, 0x0000, 0x0591, 0x3083, 0x1bd1, 0x3000, 0x07cc, 0x4090, + 0x0024, 0x3800, 0x0024, 0x3480, 0x0024, 0x4080, 0x4510, 0x3100, 0x0024, + 0x2803, 0xa105, 0x4080, 0x0024, 0x0000, 0x0595, 0x2803, 0x9d05, 0x0000, + 0x0024, 0x0000, 0x0455, 0x0000, 0x0142, 0x0004, 0x0010, 0x3613, 0x120c, + 0x1fff, 0xfb95, 0x3410, 0x3812, 0x0008, 0x0012, 0x3480, 0x4024, 0x0000, + 0x0555, 0xf1c2, 0x120c, 0x1fff, 0xfad5, 0x0006, 0x8081, 0x3480, 0xc024, + 0xff34, 0x0024, 0x48b6, 0x0024, 0x4122, 0x0024, 0x0000, 0x0142, 0x2901, + 0x9fc0, 0xf400, 0x4051, 0x000d, 0x0012, 0x0008, 0x0010, 0x0000, 0x0455, + 0x3483, 0x0024, 0x1fff, 0xfb95, 0x3410, 0x0024, 0x3480, 0x4024, 0x0000, + 0x0555, 0xf1c2, 0x120c, 0x1fff, 0xfad5, 0x0006, 0x8301, 0x3480, 0xc024, + 0xff34, 0x0024, 0x48b6, 0x0024, 0x4122, 0x0024, 0x2901, 0xce80, 0xf400, + 0x4051, 0x000d, 0x0010, 0x0000, 0x0143, 0x0000, 0x0455, 0x3483, 0x0024, + 0x1fff, 0xfb95, 0x3410, 0x0024, 0x3480, 0x4024, 0x0000, 0x0555, 0xf1c2, + 0x120c, 0x1fff, 0xfad5, 0xf1c2, 0x1202, 0x0002, 0x0001, 0x4122, 0x0024, + 0x4122, 0x0024, 0xff26, 0x4052, 0x0006, 0x8581, 0x48b6, 0x0024, 0x4122, + 0x0024, 0x2901, 0xdd00, 0xf400, 0x4051, 0xf400, 0x4510, 0x0000, 0x0551, + 0x3083, 0x1bd2, 0x3000, 0x0024, 0x6090, 0x0024, 0x0000, 0x0555, 0x0000, + 0x0041, 0x3800, 0x120c, 0x1fff, 0xfad5, 0x3480, 0x0024, 0xfe02, 0x11cc, + 0x48b2, 0x110c, 0x3411, 0x8024, 0x3491, 0xc024, 0x6cf6, 0x12cc, 0x0006, + 0x8050, 0x2803, 0x8e08, 0x0000, 0x0024, 0x0000, 0x8001, 0x3000, 0x984c, + 0x6122, 0x930c, 0x6810, 0x0024, 0x3e10, 0x0024, 0x0002, 0x0000, 0x4020, + 0x0024, 0x4020, 0x0024, 0x4020, 0x0024, 0x4020, 0x0024, 0x3e10, 0x0024, + 0x3440, 0x0024, 0xf400, 0x4011, 0x3e00, 0x054c, 0x3102, 0x0024, 0x2000, + 0x0000, 0x0003, 0xb7c8, 0x0000, 0x0455, 0x0000, 0x00c2, 0xb880, 0x920c, + 0x1fff, 0xfb95, 0x3800, 0x1b4c, 0x3410, 0x0024, 0x3480, 0x4024, 0xac22, + 0x4513, 0x3373, 0x0024, 0x3373, 0x0024, 0x3353, 0x0024, 0x3310, 0x8024, + 0x33f0, 0xc024, 0x6dc2, 0x0024, 0x3b10, 0x0024, 0x3bf0, 0x4024, 0x0000, + 0x04d5, 0x3483, 0x0024, 0x1fff, 0xfb15, 0x3410, 0x0024, 0x3480, 0x4024, + 0x4c82, 0x0024, 0x0000, 0x0024, 0x2803, 0xc209, 0x0000, 0x0024, 0x3433, + 0x0024, 0x3410, 0x0024, 0x34c0, 0x4024, 0x4c82, 0x0024, 0x0000, 0x0024, + 0x2803, 0xc209, 0x0000, 0x0024, 0x34c3, 0x0024, 0x3444, 0x0024, 0x3073, + 0x0024, 0x3063, 0x0024, 0x3000, 0x0024, 0x4080, 0x0024, 0x0000, 0x0591, + 0x2803, 0x50c5, 0x0000, 0x0455, 0x2803, 0xd9c0, 0xb880, 0x0024, 0x6890, + 0x184c, 0x3e10, 0x104c, 0xb880, 0x0024, 0x3e10, 0x0024, 0xf400, 0x4500, + 0x3e10, 0x12cc, 0x3440, 0x0024, 0xf400, 0x4010, 0x3e00, 0x004c, 0x3002, + 0x0024, 0x2000, 0x0000, 0x0003, 0xc588, 0x36c3, 0x10cc, 0xf400, 0x4511, + 0x3110, 0x934c, 0x31f0, 0xc024, 0x4d96, 0x0024, 0x3910, 0x8024, 0x39f0, + 0xc024, 0x3433, 0x184c, 0x3410, 0x0024, 0x34c0, 0x4024, 0x4c82, 0x0024, + 0x0000, 0x0040, 0x2803, 0xc2d5, 0x0000, 0x0024, 0x0000, 0x0100, 0x3e10, + 0x104c, 0xb880, 0x0024, 0x3e10, 0x0024, 0xf400, 0x4500, 0x3e10, 0x12cc, + 0x3440, 0x0024, 0xf400, 0x4010, 0x3e00, 0x004c, 0x3002, 0x0024, 0x2000, + 0x0000, 0x0003, 0xcc08, 0x0000, 0x0101, 0x6012, 0x094c, 0x3200, 0x1b0c, + 0x2803, 0xcdc1, 0x3073, 0x0024, 0x2803, 0xd9c0, 0x4480, 0x0024, 0x4080, + 0x014c, 0x3070, 0x0024, 0x2803, 0xcfd5, 0x0000, 0x0024, 0x4080, 0x01cc, + 0x0000, 0x0024, 0x2803, 0x2885, 0x3053, 0x0024, 0x32b0, 0x024c, 0x3009, + 0x024c, 0x4080, 0x02cc, 0x0000, 0x0024, 0x2803, 0xd605, 0x0000, 0x0024, + 0x34b3, 0x0024, 0x3450, 0x0024, 0x4080, 0x0024, 0x0000, 0x0184, 0x2803, + 0xd605, 0x0006, 0x0ec0, 0x34b3, 0x0024, 0x3454, 0x0024, 0x2803, 0xd600, + 0x3800, 0x0024, 0x6898, 0x12cc, 0x3450, 0x0024, 0x4080, 0x0024, 0x0006, + 0x1440, 0x2803, 0xd605, 0x0000, 0x0024, 0x34b3, 0x0024, 0x3454, 0x0024, + 0x3800, 0x0024, 0x34c3, 0x0024, 0x3404, 0x0024, 0x3073, 0x0024, 0x3063, + 0x0024, 0x3000, 0x0024, 0x4080, 0x1110, 0x0000, 0x0000, 0x2803, 0xd945, + 0x3073, 0x0024, 0x0000, 0x0144, 0x34c3, 0x0024, 0x3444, 0x0024, 0x3073, + 0x0024, 0x3063, 0x0024, 0x4480, 0x2000, 0x36f4, 0xc024, 0x36f4, 0x5812, + 0x36f1, 0xd810, 0x36f1, 0x5806, 0x36f0, 0xd804, 0x36f0, 0x5802, 0x3405, + 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, + 0xb386, 0x40d7, 0x4284, 0x184c, 0x0000, 0x05c0, 0x2803, 0xde15, 0xf5d8, + 0x3804, 0x0000, 0x0984, 0x6400, 0xb84a, 0x3e13, 0xf80d, 0xa204, 0x380e, + 0x0000, 0x800a, 0x0000, 0x00ce, 0x2403, 0xe14e, 0xffa4, 0x0024, 0x48b6, + 0x0024, 0x0000, 0x0024, 0x2803, 0xe144, 0x4000, 0x40c2, 0x4224, 0x0024, + 0x6090, 0x0024, 0xffa4, 0x0024, 0x0fff, 0xfe83, 0xfe86, 0x1bce, 0x36f3, + 0xd80d, 0x48b6, 0x0024, 0x0fff, 0xff03, 0xa230, 0x45c3, 0x2000, 0x0000, + 0x36f1, 0x180a, 0x0007, 0x0001, /*copy 1*/ + 0x802e, 0x0006, 0x0002, /*copy 2*/ + 0x2801, 0x6a00, 0x0007, 0x0001, /*copy 1*/ + 0x8030, 0x0006, 0x0002, /*copy 2*/ + 0x2800, 0x1b40, 0x0007, 0x0001, /*copy 1*/ + 0x8028, 0x0006, 0x0002, /*copy 2*/ + 0x2a00, 0x144e, 0x0007, 0x0001, /*copy 1*/ + 0x8032, 0x0006, 0x0002, /*copy 2*/ + 0x2800, 0x7280, 0x0007, 0x0001, /*copy 1*/ + 0x3580, 0x0006, 0x8038, 0x0000, /*Rle(56)*/ + 0x0007, 0x0001, /*copy 1*/ + 0xfab3, 0x0006, 0x0254, /*copy 596*/ + 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, 0xffff, 0xfffe, 0xfffb, 0xfff9, + 0xfff5, 0xfff2, 0xffed, 0xffe8, 0xffe3, 0xffde, 0xffd8, 0xffd3, 0xffce, + 0xffca, 0xffc7, 0xffc4, 0xffc4, 0xffc5, 0xffc7, 0xffcc, 0xffd3, 0xffdc, + 0xffe6, 0xfff3, 0x0001, 0x0010, 0x001f, 0x002f, 0x003f, 0x004e, 0x005b, + 0x0066, 0x006f, 0x0074, 0x0075, 0x0072, 0x006b, 0x005f, 0x004f, 0x003c, + 0x0024, 0x0009, 0xffed, 0xffcf, 0xffb0, 0xff93, 0xff77, 0xff5f, 0xff4c, + 0xff3d, 0xff35, 0xff34, 0xff3b, 0xff4a, 0xff60, 0xff7e, 0xffa2, 0xffcd, + 0xfffc, 0x002e, 0x0061, 0x0094, 0x00c4, 0x00f0, 0x0114, 0x0131, 0x0144, + 0x014b, 0x0146, 0x0134, 0x0116, 0x00eb, 0x00b5, 0x0075, 0x002c, 0xffde, + 0xff8e, 0xff3d, 0xfeef, 0xfea8, 0xfe6a, 0xfe39, 0xfe16, 0xfe05, 0xfe06, + 0xfe1b, 0xfe43, 0xfe7f, 0xfecd, 0xff2a, 0xff95, 0x0009, 0x0082, 0x00fd, + 0x0173, 0x01e1, 0x0242, 0x0292, 0x02cc, 0x02ec, 0x02f2, 0x02da, 0x02a5, + 0x0253, 0x01e7, 0x0162, 0x00c9, 0x0021, 0xff70, 0xfebc, 0xfe0c, 0xfd68, + 0xfcd5, 0xfc5b, 0xfc00, 0xfbc9, 0xfbb8, 0xfbd2, 0xfc16, 0xfc85, 0xfd1b, + 0xfdd6, 0xfeae, 0xff9e, 0x009c, 0x01a0, 0x02a1, 0x0392, 0x046c, 0x0523, + 0x05b0, 0x060a, 0x062c, 0x0613, 0x05bb, 0x0526, 0x0456, 0x0351, 0x021f, + 0x00c9, 0xff5a, 0xfde1, 0xfc6a, 0xfb05, 0xf9c0, 0xf8aa, 0xf7d0, 0xf73d, + 0xf6fa, 0xf70f, 0xf77e, 0xf848, 0xf96b, 0xfadf, 0xfc9a, 0xfe8f, 0x00ad, + 0x02e3, 0x051a, 0x073f, 0x0939, 0x0af4, 0x0c5a, 0x0d59, 0x0de1, 0x0de5, + 0x0d5c, 0x0c44, 0x0a9e, 0x0870, 0x05c7, 0x02b4, 0xff4e, 0xfbaf, 0xf7f8, + 0xf449, 0xf0c7, 0xed98, 0xeae0, 0xe8c4, 0xe765, 0xe6e3, 0xe756, 0xe8d2, + 0xeb67, 0xef19, 0xf3e9, 0xf9cd, 0x00b5, 0x088a, 0x112b, 0x1a72, 0x2435, + 0x2e42, 0x3866, 0x426b, 0x4c1b, 0x553e, 0x5da2, 0x6516, 0x6b6f, 0x7087, + 0x7441, 0x7686, 0x774a, 0x7686, 0x7441, 0x7087, 0x6b6f, 0x6516, 0x5da2, + 0x553e, 0x4c1b, 0x426b, 0x3866, 0x2e42, 0x2435, 0x1a72, 0x112b, 0x088a, + 0x00b5, 0xf9cd, 0xf3e9, 0xef19, 0xeb67, 0xe8d2, 0xe756, 0xe6e3, 0xe765, + 0xe8c4, 0xeae0, 0xed98, 0xf0c7, 0xf449, 0xf7f8, 0xfbaf, 0xff4e, 0x02b4, + 0x05c7, 0x0870, 0x0a9e, 0x0c44, 0x0d5c, 0x0de5, 0x0de1, 0x0d59, 0x0c5a, + 0x0af4, 0x0939, 0x073f, 0x051a, 0x02e3, 0x00ad, 0xfe8f, 0xfc9a, 0xfadf, + 0xf96b, 0xf848, 0xf77e, 0xf70f, 0xf6fa, 0xf73d, 0xf7d0, 0xf8aa, 0xf9c0, + 0xfb05, 0xfc6a, 0xfde1, 0xff5a, 0x00c9, 0x021f, 0x0351, 0x0456, 0x0526, + 0x05bb, 0x0613, 0x062c, 0x060a, 0x05b0, 0x0523, 0x046c, 0x0392, 0x02a1, + 0x01a0, 0x009c, 0xff9e, 0xfeae, 0xfdd6, 0xfd1b, 0xfc85, 0xfc16, 0xfbd2, + 0xfbb8, 0xfbc9, 0xfc00, 0xfc5b, 0xfcd5, 0xfd68, 0xfe0c, 0xfebc, 0xff70, + 0x0021, 0x00c9, 0x0162, 0x01e7, 0x0253, 0x02a5, 0x02da, 0x02f2, 0x02ec, + 0x02cc, 0x0292, 0x0242, 0x01e1, 0x0173, 0x00fd, 0x0082, 0x0009, 0xff95, + 0xff2a, 0xfecd, 0xfe7f, 0xfe43, 0xfe1b, 0xfe06, 0xfe05, 0xfe16, 0xfe39, + 0xfe6a, 0xfea8, 0xfeef, 0xff3d, 0xff8e, 0xffde, 0x002c, 0x0075, 0x00b5, + 0x00eb, 0x0116, 0x0134, 0x0146, 0x014b, 0x0144, 0x0131, 0x0114, 0x00f0, + 0x00c4, 0x0094, 0x0061, 0x002e, 0xfffc, 0xffcd, 0xffa2, 0xff7e, 0xff60, + 0xff4a, 0xff3b, 0xff34, 0xff35, 0xff3d, 0xff4c, 0xff5f, 0xff77, 0xff93, + 0xffb0, 0xffcf, 0xffed, 0x0009, 0x0024, 0x003c, 0x004f, 0x005f, 0x006b, + 0x0072, 0x0075, 0x0074, 0x006f, 0x0066, 0x005b, 0x004e, 0x003f, 0x002f, + 0x001f, 0x0010, 0x0001, 0xfff3, 0xffe6, 0xffdc, 0xffd3, 0xffcc, 0xffc7, + 0xffc5, 0xffc4, 0xffc4, 0xffc7, 0xffca, 0xffce, 0xffd3, 0xffd8, 0xffde, + 0xffe3, 0xffe8, 0xffed, 0xfff2, 0xfff5, 0xfff9, 0xfffb, 0xfffe, 0xffff, + 0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, 0x0164, 0x04b9, 0x09a5, + 0x0d57, 0x045f, 0xe8cd, 0xbc5c, 0x9380, 0xa08d, 0x0c3f, 0x1d7a, 0x43d9, + 0x68b4, 0x7fff, 0x7fff, 0x68b4, 0x43d9, 0x1d7a, 0x0c3f, 0xa08d, 0x9380, + 0xbc5c, 0xe8cd, 0x045f, 0x0d57, 0x09a5, 0x04b9, 0x0164, 0xfd25, 0xfb12, + 0x1042, 0x253f, 0xd5bc, 0xed41, 0x08de, 0x53f7, 0x7fff, 0x53f7, 0x08de, + 0xed41, 0xd5bc, 0x253f, 0x1042, 0xfb12, 0xfd25, 0x0006, 0x0000, 0xfff7, + 0x0000, 0x0012, 0x0000, 0xffe4, 0x0000, 0x002e, 0x0000, 0xffbb, 0x0000, + 0x0067, 0x0000, 0xff6f, 0x0000, 0x00cb, 0x0000, 0xfeed, 0x0000, 0x0170, + 0x0000, 0xfe1d, 0x0000, 0x0274, 0x0000, 0xfcde, 0x0000, 0x03f8, 0x0000, + 0xfb0a, 0x0000, 0x0629, 0x0000, 0xf86c, 0x0000, 0x0943, 0x0000, 0xf4c1, + 0x0000, 0x0d9a, 0x0000, 0xef9e, 0x0000, 0x13b4, 0x0000, 0xe851, 0x0000, + 0x1c8a, 0x0000, 0xdd72, 0x0000, 0x2a3c, 0x0000, 0xcb94, 0x0000, 0x42bd, + 0x0000, 0xa75f, 0x0000, 0x7f22, 0x0000, 0xe516, 0x0000, 0x5168, 0x7fff, + 0x5168, 0x0000, 0xe516, 0x0000, 0x7f22, 0x0000, 0xa75f, 0x0000, 0x42bd, + 0x0000, 0xcb94, 0x0000, 0x2a3c, 0x0000, 0xdd72, 0x0000, 0x1c8a, 0x0000, + 0xe851, 0x0000, 0x13b4, 0x0000, 0xef9e, 0x0000, 0x0d9a, 0x0000, 0xf4c1, + 0x0000, 0x0943, 0x0000, 0xf86c, 0x0000, 0x0629, 0x0000, 0xfb0a, 0x0000, + 0x03f8, 0x0000, 0xfcde, 0x0000, 0x0274, 0x0000, 0xfe1d, 0x0000, 0x0170, + 0x0000, 0xfeed, 0x0000, 0x00cb, 0x0000, 0xff6f, 0x0000, 0x0067, 0x0000, + 0xffbb, 0x0000, 0x002e, 0x0000, 0xffe4, 0x0000, 0x0012, 0x0000, 0xfff7, + 0x0000, 0x0006, 0x0007, 0x0001, /*copy 1*/ + 0x180b, 0x0006, 0x0064, /*copy 100*/ + 0x000f, 0x0010, 0x001c, 0xfab3, 0x3580, 0x8037, 0xa037, 0x0001, 0x0000, + 0x3580, 0x01a4, 0x0046, 0x006f, 0x0072, 0x006d, 0x0061, 0x0074, 0x0020, + 0x004e, 0x006f, 0x0074, 0x0020, 0x0044, 0x0053, 0x0046, 0x002f, 0x0044, + 0x0046, 0x0046, 0x0000, 0x004f, 0x006b, 0x0000, 0x004e, 0x006f, 0x0074, + 0x0020, 0x0032, 0x0020, 0x0063, 0x0068, 0x0061, 0x006e, 0x006e, 0x0065, + 0x006c, 0x0073, 0x0000, 0x0049, 0x006e, 0x0076, 0x0061, 0x006c, 0x0069, + 0x0064, 0x0020, 0x0044, 0x0053, 0x0044, 0x0020, 0x0062, 0x0069, 0x0074, + 0x0073, 0x0074, 0x0072, 0x0065, 0x0061, 0x006d, 0x0000, 0x004e, 0x006f, + 0x0074, 0x0020, 0x0044, 0x0053, 0x0044, 0x0020, 0x0062, 0x0069, 0x0074, + 0x0073, 0x0074, 0x0072, 0x0065, 0x0061, 0x006d, 0x0000, 0xff2f, 0x0295, + 0x0a83, 0x16ef, 0x2912, 0x3215, 0x3215, 0x2912, 0x16ef, 0x0a83, 0x0295, + 0xff2f, 0x0007, 0x0001, /*copy 1*/ + 0x8025, 0x0006, 0x0002, /*copy 2*/ + 0x2a00, 0x5d8e, 0x0007, 0x0001, /*copy 1*/ + 0x1a00, 0x0006, 0x0020, /*copy 32*/ + 0x0046, 0x0046, 0x0055, 0x1a40, 0xfc57, 0x0000, 0x0000, 0x0055, 0x1a60, + 0xfc57, 0x0000, 0x0000, 0x0000, 0x1a80, 0xfc73, 0x0000, 0x0000, 0x0000, + 0x1aa0, 0xfc73, 0x0000, 0x0000, 0x0000, 0x3000, 0xfc84, 0x0000, 0x0000, + 0x0000, 0x3200, 0xfc84, 0x0000, 0x0000, 0x0007, 0x0001, /*copy 1*/ + 0x1a40, 0x0006, 0x8080, 0x0000, /*Rle(128)*/ + 0x000a, 0x0001, /*copy 1*/ + 0x0050, +#define PLUGIN_SIZE 8608 +#ifndef SKIP_PLUGIN_VARNAME +}; +#endif diff --git a/targets/esp32/components/VS1053/include/patches_flac.h b/targets/esp32/components/VS1053/include/patches_flac.h new file mode 100644 index 00000000..c74a87d1 --- /dev/null +++ b/targets/esp32/components/VS1053/include/patches_flac.h @@ -0,0 +1,961 @@ +#ifndef SKIP_PLUGIN_VARNAME +const unsigned short PLUGIN[] = { + /* Compressed plugin */ +#endif + 0x0007, 0x0001, /*copy 1*/ + 0x8050, 0x0006, 0x001e, /*copy 30*/ + 0x2a00, 0xc000, 0x3e12, 0xb817, 0x3e14, 0xf812, 0x3e01, 0xb811, 0x0007, + 0x9717, 0x0020, 0xffd2, 0x0030, 0x11d1, 0x3111, 0x8024, 0x3704, 0xc024, + 0x3b81, 0x8024, 0x3101, 0x8024, 0x3b81, 0x8024, 0x3f04, 0xc024, 0x2808, + 0x4800, 0x36f1, 0x9811, 0x0007, 0x0001, /*copy 1*/ + 0x8060, 0x0006, 0x0540, /*copy 1344*/ + 0xf400, 0x4095, 0x0000, 0x02c2, 0x6124, 0x0024, 0x0000, 0x0024, 0x2800, + 0x1ac5, 0x4192, 0x4542, 0x0000, 0x0041, 0x2000, 0x0015, 0x0030, 0x0317, + 0x2000, 0x0000, 0x3f00, 0x4024, 0x2000, 0x0000, 0x0000, 0x0000, 0x3e12, + 0x3800, 0x3e00, 0xb804, 0x0030, 0x0015, 0x0007, 0x8257, 0x3700, 0x984c, + 0xf224, 0x1444, 0xf224, 0x0024, 0x0008, 0x0002, 0x2910, 0x0181, 0x0000, + 0x1bc8, 0xb428, 0x1402, 0x0000, 0x8004, 0x2910, 0x0195, 0x0000, 0x1bc8, + 0xb428, 0x0024, 0x0006, 0x0095, 0x2800, 0x2945, 0x3e13, 0x780e, 0x3e11, + 0x7803, 0x3e13, 0xf806, 0x3e11, 0xf801, 0x3510, 0xb808, 0x003f, 0xe004, + 0xfec4, 0x3800, 0x48be, 0x17c3, 0xfec6, 0x41c2, 0x48be, 0x4497, 0x4090, + 0x1c46, 0xf06c, 0x0024, 0x2400, 0x2580, 0x6090, 0x41c3, 0x6628, 0x1c47, + 0x0000, 0x0024, 0x2800, 0x2449, 0xf07e, 0x0024, 0xf400, 0x4182, 0x673a, + 0x1c46, 0x0000, 0x0024, 0x2800, 0x2589, 0xf06c, 0x0024, 0xf400, 0x41c3, + 0x0000, 0x0024, 0x4224, 0x3442, 0x2903, 0xd9c0, 0x4336, 0x37c3, 0x0000, + 0x1805, 0x2903, 0xd9c0, 0x4508, 0x40c2, 0x450a, 0x9808, 0x0000, 0x0207, + 0xa478, 0x1bc0, 0xc45a, 0x1807, 0x0030, 0x03d5, 0x3d01, 0x5bc1, 0x36f3, + 0xd806, 0x3601, 0x5803, 0x36f3, 0x0024, 0x36f3, 0x580e, 0x0007, 0x8257, + 0x0000, 0x6004, 0x3730, 0x8024, 0xb244, 0x1c04, 0xd428, 0x3c02, 0x0006, + 0xc717, 0x2800, 0x2d05, 0x4284, 0x0024, 0x3613, 0x3c02, 0x0006, 0xc357, + 0x2901, 0x6ac0, 0x3e11, 0x5c05, 0x4284, 0x1bc5, 0x0007, 0x8257, 0x2800, + 0x3285, 0x0002, 0x0001, 0x3701, 0x0024, 0x0006, 0xc357, 0xb412, 0x9c02, + 0x002e, 0xe001, 0x2800, 0x3005, 0x6212, 0x0024, 0x0000, 0x0024, 0x2800, + 0x3295, 0x0000, 0x0024, 0x0030, 0x0117, 0x3f00, 0x0024, 0x3613, 0x0024, + 0x3e10, 0x3813, 0x3e14, 0x8024, 0x3e04, 0x8024, 0x2900, 0x4b40, 0x0006, + 0x02d3, 0x36e3, 0x0024, 0x3009, 0x1bd3, 0x0007, 0x8257, 0x3700, 0x8024, + 0xf224, 0x0024, 0x0000, 0x0024, 0x2800, 0x3491, 0x3600, 0x9844, 0x2900, + 0x3a40, 0x0000, 0x3508, 0x2911, 0xf140, 0x0000, 0x0024, 0x0030, 0x0057, + 0x3700, 0x0024, 0xf200, 0x4595, 0x0fff, 0xfe02, 0xa024, 0x164c, 0x8000, + 0x17cc, 0x3f00, 0x0024, 0x3500, 0x0024, 0x0021, 0x6d82, 0xd024, 0x44c0, + 0x0006, 0xa402, 0x2800, 0x3955, 0xd024, 0x0024, 0x0000, 0x0000, 0x2800, + 0x3955, 0x000b, 0x6d57, 0x3009, 0x3c00, 0x36f0, 0x8024, 0x36f2, 0x1800, + 0x2000, 0x0000, 0x0000, 0x0024, 0x3e14, 0x7810, 0x3e13, 0xb80d, 0x3e13, + 0xf80a, 0x3e10, 0xb803, 0x3e11, 0x3805, 0x3e11, 0xb807, 0x3e14, 0xf801, + 0x3e15, 0x3815, 0x0001, 0x000a, 0x0006, 0xc4d7, 0xbf8e, 0x9c42, 0x3e01, + 0x9c03, 0x0006, 0xa017, 0x0023, 0xffd1, 0x0007, 0x8250, 0x0fff, 0xfd85, + 0x3001, 0x0024, 0xa45a, 0x4494, 0x0000, 0x0093, 0x2800, 0x4091, 0xf25a, + 0x104c, 0x34f3, 0x0024, 0x2800, 0x4091, 0x0000, 0x0024, 0x3413, 0x084c, + 0x0000, 0x0095, 0x3281, 0xf806, 0x4091, 0x4d64, 0x2400, 0x42c0, 0x4efa, + 0x9c10, 0xf1eb, 0x6061, 0xfe55, 0x2f66, 0x5653, 0x4d64, 0x48b2, 0xa201, + 0x4efa, 0xa201, 0x36f3, 0x3c10, 0x36f5, 0x1815, 0x36f4, 0xd801, 0x36f1, + 0x9807, 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f3, 0xd80a, 0x36f3, 0x980d, + 0x2000, 0x0000, 0x36f4, 0x5810, 0x36f3, 0x0024, 0x3009, 0x3848, 0x3e14, + 0x3811, 0x3e00, 0x0024, 0x0000, 0x4000, 0x0001, 0x0010, 0x2915, 0x94c0, + 0x0001, 0xcc11, 0x36f0, 0x0024, 0x2927, 0x9e40, 0x3604, 0x1811, 0x3613, + 0x0024, 0x3e14, 0x3811, 0x3e00, 0x0024, 0x0000, 0x4000, 0x0001, 0x0010, + 0x2915, 0x94c0, 0x0001, 0xcc11, 0x36f0, 0x0024, 0x36f4, 0x1811, 0x3009, + 0x1808, 0x2000, 0x0000, 0x0000, 0x190d, 0x3613, 0x0024, 0x3e22, 0xb815, + 0x3e05, 0xb814, 0x3615, 0x0024, 0x0000, 0x800a, 0x3e13, 0x7801, 0x3e10, + 0xb803, 0x3e11, 0x3805, 0x3e11, 0xb807, 0x3e14, 0x3811, 0x3e14, 0xb813, + 0x3e03, 0xf80e, 0xb488, 0x44d5, 0x3543, 0x134c, 0x34e5, 0xc024, 0x3524, + 0x8024, 0x35a4, 0xc024, 0x3710, 0x8a0c, 0x3540, 0x4a0c, 0x3d44, 0x8024, + 0x3a10, 0x8024, 0x3590, 0x0024, 0x4010, 0x15c1, 0x6010, 0x3400, 0x3710, + 0x8024, 0x2800, 0x5704, 0x3af0, 0x8024, 0x3df0, 0x0024, 0x3591, 0x4024, + 0x3530, 0x4024, 0x4192, 0x4050, 0x6100, 0x1482, 0x4020, 0x1753, 0xbf8e, + 0x1582, 0x4294, 0x4011, 0xbd86, 0x408e, 0x2400, 0x550e, 0xfe6d, 0x2819, + 0x520e, 0x0a00, 0x5207, 0x2819, 0x4fbe, 0x0024, 0xad56, 0x904c, 0xaf5e, + 0x1010, 0xf7d4, 0x0024, 0xf7fc, 0x2042, 0x6498, 0x2046, 0x3cf4, 0x0024, + 0x3400, 0x170c, 0x4090, 0x1492, 0x35a4, 0xc024, 0x2800, 0x4f95, 0x3c00, + 0x0024, 0x4480, 0x914c, 0x36f3, 0xd80e, 0x36f4, 0x9813, 0x36f4, 0x1811, + 0x36f1, 0x9807, 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f3, 0x5801, 0x3405, + 0x9014, 0x36e3, 0x0024, 0x2000, 0x0000, 0x36f2, 0x9815, 0x2814, 0x9c91, + 0x0000, 0x004d, 0x2814, 0x9940, 0x003f, 0x0013, 0x3e12, 0xb817, 0x3e12, + 0x7808, 0x3e11, 0xb811, 0x3e15, 0x7810, 0x3e18, 0xb823, 0x3e18, 0x3821, + 0x3e10, 0x3801, 0x48b2, 0x0024, 0x3e10, 0x3801, 0x3e11, 0x3802, 0x3009, + 0x3814, 0x0030, 0x0717, 0x3f05, 0xc024, 0x0030, 0x0351, 0x3100, 0x0024, + 0x4080, 0x0024, 0x0030, 0x10d1, 0x2800, 0x6745, 0x0001, 0x800a, 0x0006, + 0x6514, 0x3111, 0x8024, 0x6894, 0x13c1, 0x6618, 0x0024, 0xfe44, 0x1000, + 0x4cb2, 0x0406, 0x3c10, 0x0024, 0x3c50, 0x4024, 0x34f0, 0x4024, 0x661c, + 0x1040, 0xfe64, 0x0024, 0x4cb2, 0x0024, 0x3cf0, 0x4024, 0xbc82, 0x3080, + 0x0030, 0x0351, 0x3100, 0x8024, 0xfea8, 0x0024, 0x5ca2, 0x0024, 0x0000, + 0x0182, 0xac22, 0x0024, 0xf7c8, 0x0024, 0x48b2, 0x0024, 0xac22, 0x0024, + 0x2800, 0x6ac0, 0xf7cc, 0x1002, 0x0030, 0x0394, 0x3400, 0x4024, 0x3100, + 0x184c, 0x0006, 0xc051, 0x291e, 0x8080, 0x0006, 0x6410, 0x4088, 0x1001, + 0x0030, 0x1111, 0x3100, 0x184c, 0x0006, 0xc051, 0x291e, 0x8080, 0x0006, + 0x6550, 0x0006, 0x6694, 0x408c, 0x1002, 0xf224, 0x0024, 0x0006, 0xa017, + 0x2800, 0x6ed5, 0x0000, 0x0024, 0x2808, 0x3f41, 0x0006, 0x6410, 0x3050, + 0x0024, 0x3000, 0x4024, 0x6014, 0x0024, 0x0000, 0x0024, 0x2800, 0x6e19, + 0x0000, 0x0024, 0xf400, 0x4040, 0x38b0, 0x0024, 0x2808, 0x3f40, 0x3800, + 0x0024, 0x2800, 0x70c1, 0xf224, 0x0024, 0x0000, 0x0024, 0x2808, 0x3f45, + 0x4684, 0x4106, 0xf12c, 0x0024, 0xf148, 0x0024, 0x846c, 0x0024, 0x2808, + 0x3f40, 0xf400, 0x4184, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, + 0x3625, 0x0024, 0x0000, 0x800a, 0x3e10, 0x3801, 0x3e10, 0xb803, 0x3e11, + 0x3805, 0x3e11, 0xb807, 0x3e14, 0x3811, 0x0006, 0xa090, 0x2912, 0x0d00, + 0x3e14, 0xc024, 0x4088, 0x8000, 0x4080, 0x0024, 0x0007, 0x90d1, 0x2800, + 0x7705, 0x0000, 0x0024, 0x0007, 0x9051, 0x3100, 0x4024, 0x4100, 0x0024, + 0x3900, 0x0024, 0x0007, 0x90d1, 0x0004, 0x0000, 0x31f0, 0x4024, 0x6014, + 0x0400, 0x0000, 0x0024, 0x2800, 0x7b51, 0x4080, 0x0024, 0x0000, 0x0000, + 0x2800, 0x7ac5, 0x0000, 0x0024, 0x0007, 0x9053, 0x3300, 0x0024, 0x4080, + 0x0024, 0x0000, 0x0000, 0x2800, 0x7b58, 0x0000, 0x0024, 0x0007, 0x9051, + 0x3900, 0x0024, 0x3200, 0x504c, 0x6410, 0x0024, 0x3cf0, 0x0000, 0x4080, + 0x0024, 0x0006, 0xc691, 0x2800, 0x9405, 0x3009, 0x0400, 0x0007, 0x9051, + 0x0000, 0x1001, 0x3100, 0x0024, 0x6012, 0x0024, 0x0006, 0xc6d0, 0x2800, + 0x8849, 0x003f, 0xe000, 0x0006, 0xc693, 0x3900, 0x0c00, 0x3009, 0x0001, + 0x6014, 0x0024, 0x0007, 0x1ad0, 0x2800, 0x8855, 0x3009, 0x0000, 0x4080, + 0x0024, 0x0000, 0x0301, 0x2800, 0x8245, 0x4090, 0x0024, 0x0000, 0x0024, + 0x2800, 0x8355, 0x0000, 0x0024, 0x3009, 0x0000, 0xc012, 0x0024, 0x2800, + 0x8840, 0x3009, 0x2001, 0x3009, 0x0000, 0x6012, 0x0024, 0x0000, 0x0341, + 0x2800, 0x8555, 0x0000, 0x0024, 0x6190, 0x0024, 0x2800, 0x8840, 0x3009, + 0x2000, 0x6012, 0x0024, 0x0000, 0x0381, 0x2800, 0x8715, 0x0000, 0x0024, + 0x6190, 0x0024, 0x2800, 0x8840, 0x3009, 0x2000, 0x6012, 0x0024, 0x0000, + 0x00c0, 0x2800, 0x8855, 0x0000, 0x0024, 0x3009, 0x2000, 0x0006, 0xa090, + 0x3009, 0x0000, 0x4080, 0x0024, 0x0000, 0x0081, 0x2800, 0x8d15, 0x0007, + 0x8c13, 0x3300, 0x104c, 0xb010, 0x0024, 0x0002, 0x8001, 0x2800, 0x8f85, + 0x34f0, 0x0024, 0x2800, 0x8d00, 0x0000, 0x0024, 0x0006, 0xc351, 0x3009, + 0x0000, 0x6090, 0x0024, 0x3009, 0x2000, 0x2900, 0x0b80, 0x3009, 0x0405, + 0x0006, 0xc690, 0x0006, 0xc6d1, 0x3009, 0x0000, 0x3009, 0x0401, 0x6014, + 0x0024, 0x0006, 0xa093, 0x2800, 0x8b91, 0xb880, 0x0024, 0x2800, 0x9cc0, + 0x3009, 0x2c00, 0x4040, 0x0024, 0x6012, 0x0024, 0x0006, 0xc6d0, 0x2800, + 0x9cd8, 0x0000, 0x0024, 0x0006, 0xc693, 0x3009, 0x0c00, 0x3009, 0x0001, + 0x6014, 0x0024, 0x0006, 0xc350, 0x2800, 0x9cc1, 0x0000, 0x0024, 0x6090, + 0x0024, 0x3009, 0x2c00, 0x3009, 0x0005, 0x2900, 0x0b80, 0x0000, 0x9cc8, + 0x3009, 0x0400, 0x4080, 0x0024, 0x0003, 0x8000, 0x2800, 0x9cc5, 0x0000, + 0x0024, 0x6400, 0x0024, 0x0000, 0x0081, 0x2800, 0x9cc9, 0x0000, 0x0024, + 0x0007, 0x8c13, 0x3300, 0x0024, 0xb010, 0x0024, 0x0006, 0xc650, 0x2800, + 0x9cd5, 0x0000, 0x0024, 0x0001, 0x0002, 0x3413, 0x0000, 0x3009, 0x0401, + 0x4010, 0x8406, 0x0000, 0x0281, 0xa010, 0x13c1, 0x4122, 0x0024, 0x0000, + 0x03c2, 0x6122, 0x8002, 0x462c, 0x0024, 0x469c, 0x0024, 0xfee2, 0x0024, + 0x48be, 0x0024, 0x6066, 0x8400, 0x0006, 0xc350, 0x2800, 0x9cc1, 0x0000, + 0x0024, 0x4090, 0x0024, 0x3009, 0x2400, 0x2900, 0x0b80, 0x3009, 0x0005, + 0x0007, 0x1b50, 0x2912, 0x0d00, 0x3613, 0x0024, 0x3a00, 0x0380, 0x4080, + 0x0024, 0x0000, 0x00c1, 0x2800, 0xa585, 0x3009, 0x0000, 0xb010, 0x008c, + 0x4192, 0x0024, 0x6012, 0x0024, 0x0006, 0xf051, 0x2800, 0xa398, 0x3009, + 0x0400, 0x0007, 0x1fd1, 0x30e3, 0x0400, 0x4080, 0x0024, 0x0000, 0x0301, + 0x2800, 0xa585, 0x3009, 0x0000, 0xb010, 0x0024, 0x0000, 0x0101, 0x6012, + 0x0024, 0x0006, 0xf051, 0x2800, 0xa595, 0x0000, 0x0024, 0x3023, 0x0400, + 0xf200, 0x184c, 0xb880, 0xa400, 0x3009, 0x2000, 0x3009, 0x0441, 0x3e10, + 0x4402, 0x2909, 0xa9c0, 0x3e10, 0x8024, 0x36e3, 0x0024, 0x36f4, 0xc024, + 0x36f4, 0x1811, 0x36f1, 0x9807, 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f0, + 0x1801, 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, + 0x36f2, 0x9817, 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, + 0xb814, 0x3615, 0x0024, 0x0000, 0x800a, 0x3e10, 0xb803, 0x0012, 0x5103, + 0x3e11, 0x3805, 0x3e11, 0xb807, 0x3e14, 0x380d, 0x0030, 0x0250, 0x3e13, + 0xf80e, 0xbe8b, 0x83e0, 0x290c, 0x4840, 0x3613, 0x0024, 0x290c, 0x4840, + 0x4086, 0x984c, 0x0000, 0x00ce, 0x2400, 0xaf8e, 0x3009, 0x1bc0, 0x0000, + 0x01c3, 0xae3a, 0x184c, 0x0000, 0x0043, 0x3009, 0x3842, 0x290c, 0x4840, + 0x3009, 0x3840, 0x4084, 0x9bc0, 0xfe26, 0x9bc2, 0xceba, 0x0024, 0x4e8e, + 0x0024, 0x4e9a, 0x0024, 0x4f8e, 0x0024, 0x0000, 0x0102, 0x2800, 0xb4c5, + 0x0030, 0x0010, 0x0000, 0x0206, 0x3613, 0x0024, 0x290c, 0x4840, 0x3009, + 0x3840, 0x3000, 0xdbc0, 0xb366, 0x0024, 0x0000, 0x0024, 0x2800, 0xb4d5, + 0x4e8e, 0x0024, 0x4e9a, 0x0024, 0x4f8e, 0x0024, 0x0030, 0x0010, 0x2800, + 0xb195, 0x0000, 0x0206, 0x36f3, 0xd80e, 0x36f4, 0x180d, 0x36f1, 0x9807, + 0x36f1, 0x1805, 0x36f0, 0x9803, 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, + 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x3e10, 0xb812, 0x3e11, 0xb810, + 0x3e12, 0x0024, 0x0006, 0x9f92, 0x0025, 0xffd0, 0x3e04, 0x4bd1, 0x3181, + 0xf847, 0xb68c, 0x4440, 0x3009, 0x0802, 0x6024, 0x3806, 0x0006, 0x8a10, + 0x2903, 0xa905, 0x0000, 0xb948, 0x0000, 0x0800, 0x6101, 0x1602, 0xaf2e, + 0x0024, 0x4214, 0x1be3, 0xaf0e, 0x1811, 0x0fff, 0xfc00, 0xb200, 0x9bc7, + 0x0000, 0x03c0, 0x2800, 0xbd85, 0xb204, 0xa002, 0x2903, 0x6b00, 0x3613, + 0x2002, 0x4680, 0x1bc8, 0x36f1, 0x9810, 0x2000, 0x0000, 0x36f0, 0x9812, + 0x2a08, 0x1b8e, 0x2803, 0x8c80, 0x0000, 0xbe97, 0x0006, 0xd397, 0x2000, + 0x0000, 0x3f00, 0x0024, 0x0007, 0x0001, /*copy 1*/ + 0x8300, 0x0006, 0x191e, /*copy 6430*/ + 0x0030, 0x0055, 0xb080, 0x1402, 0x0fdf, 0xffc1, 0x0007, 0x9257, 0xb212, + 0x3c00, 0x3d00, 0x4024, 0x0006, 0x0097, 0x3f10, 0x0024, 0x3f00, 0x0024, + 0x0030, 0x0297, 0x3f00, 0x0024, 0x0007, 0x9017, 0x3f00, 0x0024, 0x0007, + 0x81d7, 0x3f10, 0x0024, 0xc090, 0x3c00, 0x0006, 0x0297, 0xb080, 0x3c00, + 0x0000, 0x0401, 0x000a, 0x1055, 0x0006, 0x0017, 0x3f10, 0x3401, 0x000a, + 0x2795, 0x3f00, 0x3401, 0x0001, 0x6a97, 0xf400, 0x55c0, 0x0000, 0x0817, + 0xb080, 0x57c0, 0x0014, 0x958f, 0x0000, 0x5b4e, 0x0030, 0x0017, 0x3700, + 0x0024, 0x0004, 0x0001, 0xb012, 0x0024, 0x0000, 0x004d, 0x280f, 0xe115, + 0x0006, 0x2016, 0x0006, 0x01d7, 0x3f00, 0x0024, 0x0000, 0x190d, 0x000f, + 0xf94f, 0x0000, 0xcd0e, 0x280f, 0xe100, 0x0006, 0x2016, 0x0000, 0x0080, + 0x0005, 0x4f92, 0x2909, 0xf840, 0x3613, 0x2800, 0x0006, 0x0197, 0x0006, + 0xa115, 0xb080, 0x0024, 0x3f00, 0x3400, 0x0007, 0x8a57, 0x3700, 0x0024, + 0x4080, 0x0024, 0x0000, 0x0040, 0x2800, 0xced5, 0x0006, 0xa2d7, 0x3009, + 0x3c00, 0x0006, 0xa157, 0x3009, 0x1c00, 0x0006, 0x01d7, 0x0000, 0x190d, + 0x000a, 0x708f, 0x0000, 0xd7ce, 0x290b, 0x1a80, 0x3f00, 0x184c, 0x0030, + 0x0017, 0x4080, 0x1c01, 0x0000, 0x0200, 0x2800, 0xcb15, 0xb102, 0x0024, + 0x0000, 0xcd08, 0x2800, 0xcb15, 0x0000, 0xd3ce, 0x0011, 0x210f, 0x0000, + 0x190d, 0x280f, 0xcb00, 0x3613, 0x0024, 0x0006, 0xa115, 0x0006, 0x01d7, + 0x37f0, 0x1401, 0x6100, 0x1c01, 0x4012, 0x0024, 0x0000, 0x8000, 0x6010, + 0x0024, 0x34f3, 0x0400, 0x2800, 0xd698, 0x0000, 0x0024, 0x0000, 0x8001, + 0x6010, 0x3c01, 0x0000, 0x000d, 0x2811, 0x8259, 0x0000, 0x0024, 0x2a11, + 0x2100, 0x0030, 0x0257, 0x3700, 0x0024, 0x4080, 0x0024, 0x0000, 0x0024, + 0x2800, 0xd9d5, 0x0006, 0x0197, 0x0006, 0xa115, 0x3f00, 0x3400, 0x003f, + 0xc000, 0xb600, 0x41c1, 0x0012, 0x5103, 0x000c, 0xc002, 0xdcd6, 0x0024, + 0x0019, 0xd4c2, 0x2800, 0xa845, 0x0001, 0x1188, 0x0013, 0xd9c3, 0x6fd6, + 0x0024, 0x0000, 0x190d, 0x2800, 0xdf95, 0x0014, 0x1b01, 0x0020, 0x480f, + 0x0000, 0xde4e, 0x0000, 0x190d, 0x2820, 0x41c0, 0x0001, 0x1188, 0x0039, + 0x324f, 0x0001, 0x3e8e, 0x2820, 0x4a18, 0xb882, 0x0024, 0x2a20, 0x48c0, + 0x003f, 0xfd00, 0xb700, 0x0024, 0x003f, 0xf901, 0x6010, 0x0024, 0x0000, + 0x0024, 0x280a, 0xc505, 0x0000, 0x190d, 0x0014, 0x1b01, 0x0015, 0x59c0, + 0x6fc2, 0x0024, 0x0019, 0x9301, 0x2800, 0xe9d5, 0x0018, 0x50c0, 0x290c, + 0x4840, 0x3613, 0x0024, 0x290c, 0x4840, 0x4086, 0x184c, 0x0000, 0x18c2, + 0x6234, 0x0024, 0x0000, 0x1d02, 0x2800, 0xe5d5, 0x6234, 0x0024, 0x0030, + 0x0317, 0x2800, 0xeb40, 0x3f00, 0x0024, 0x0000, 0x1d82, 0x2800, 0xe855, + 0x6234, 0x0024, 0x2912, 0x0d00, 0x4084, 0x184c, 0xf200, 0x0024, 0x6200, + 0x0024, 0x0006, 0x0017, 0x2800, 0xe540, 0xb080, 0x3c40, 0x0000, 0x0202, + 0x2800, 0xeb55, 0xa024, 0x0024, 0xc020, 0x0024, 0x2800, 0xe540, 0x0030, + 0x02d7, 0x6fc2, 0x0024, 0x0000, 0x0024, 0x2800, 0xeb55, 0x0000, 0x0024, + 0x2803, 0x2240, 0x000a, 0xcac8, 0x000a, 0x8c8f, 0x0000, 0xec8e, 0x000c, + 0x0981, 0x280a, 0x71c0, 0x002c, 0x9d40, 0x000a, 0x708f, 0x0000, 0xd7ce, + 0x280a, 0xc0d5, 0x0012, 0x5182, 0x6fd6, 0x0024, 0x003f, 0xfd81, 0x280a, + 0x8e45, 0xb710, 0x0024, 0xb710, 0x0024, 0x003f, 0xfc01, 0x6012, 0x0024, + 0x0000, 0x0101, 0x2801, 0x0855, 0xffd2, 0x0024, 0x48b2, 0x0024, 0x4190, + 0x0024, 0x0000, 0x190d, 0x2801, 0x0855, 0x0030, 0x0250, 0xb880, 0x104c, + 0x3cf0, 0x0024, 0x0010, 0x5500, 0xb880, 0x23c0, 0xb882, 0x2000, 0x0007, + 0x8590, 0x2914, 0xbec0, 0x0000, 0x0440, 0x0007, 0x8b50, 0xb880, 0x0024, + 0x2920, 0x0100, 0x3800, 0x0024, 0x2920, 0x0000, 0x0006, 0x8a91, 0x0000, + 0x0800, 0xb880, 0xa440, 0x003f, 0xfd81, 0xb710, 0xa7c0, 0x003f, 0xfc01, + 0x6012, 0x0024, 0x0000, 0x0101, 0x2801, 0x1195, 0x0000, 0x0024, 0xffe2, + 0x0024, 0x48b2, 0x0024, 0x4190, 0x0024, 0x0000, 0x0024, 0x2801, 0x1195, + 0x0000, 0x0024, 0x2912, 0x2d80, 0x0000, 0x0780, 0x4080, 0x0024, 0x0006, + 0x8a90, 0x2801, 0x1195, 0x0000, 0x01c2, 0xb886, 0x8040, 0x3613, 0x03c1, + 0xbcd2, 0x0024, 0x0030, 0x0011, 0x2800, 0xfe15, 0x003f, 0xff42, 0xb886, + 0x8040, 0x3009, 0x03c1, 0x0000, 0x0020, 0xac22, 0x0024, 0x0000, 0x0102, + 0x6cd2, 0x0024, 0x3e10, 0x0024, 0x2909, 0x8c80, 0x3e00, 0x4024, 0x36f3, + 0x0024, 0x3e11, 0x8024, 0x3e01, 0xc024, 0x2901, 0x3540, 0x0000, 0x0201, + 0xf400, 0x4512, 0x2900, 0x0c80, 0x3213, 0x1b8c, 0x3100, 0x0024, 0xb010, + 0x0024, 0x0000, 0x0024, 0x2801, 0x1195, 0x0000, 0x0024, 0x291a, 0x8a40, + 0x0000, 0x0100, 0x2920, 0x0200, 0x3633, 0x0024, 0x2920, 0x0280, 0x0000, + 0x0401, 0x408e, 0x0024, 0x2920, 0x0280, 0x0000, 0x0401, 0x003f, 0xfd81, + 0xb710, 0x4006, 0x003f, 0xfc01, 0x6012, 0x0024, 0x0000, 0x0101, 0x2801, + 0x1195, 0x0000, 0x0024, 0xffe2, 0x0024, 0x48b2, 0x0024, 0x4190, 0x0024, + 0x0000, 0x0024, 0x2801, 0x1195, 0x0000, 0x0024, 0x2912, 0x2d80, 0x0000, + 0x0780, 0x4080, 0x0024, 0x0000, 0x01c2, 0x2800, 0xfa05, 0x0006, 0x8a90, + 0x2a01, 0x1180, 0x2920, 0x0100, 0x0000, 0x0401, 0x0000, 0x0180, 0x2920, + 0x0200, 0x3613, 0x0024, 0x2920, 0x0280, 0x3613, 0x0024, 0x0000, 0x0401, + 0x2920, 0x0280, 0x4084, 0x984c, 0x0019, 0x9d01, 0x6212, 0x0024, 0x001e, + 0x5c01, 0x2801, 0x0cd5, 0x6012, 0x0024, 0x0000, 0x0024, 0x2801, 0x0ec5, + 0x0000, 0x0024, 0x001b, 0x5bc1, 0x6212, 0x0024, 0x001b, 0xdd81, 0x2801, + 0x1295, 0x6012, 0x0024, 0x0000, 0x0024, 0x2801, 0x1295, 0x0000, 0x0024, + 0x0000, 0x004d, 0x000a, 0xbf4f, 0x280a, 0xb880, 0x0001, 0x0fce, 0x0020, + 0xfb4f, 0x0000, 0x190d, 0x0001, 0x16ce, 0x2920, 0xf440, 0x3009, 0x2bc1, + 0x291a, 0x8a40, 0x36e3, 0x0024, 0x0000, 0x190d, 0x000a, 0x708f, 0x280a, + 0xcac0, 0x0000, 0xd7ce, 0x0030, 0x0017, 0x3700, 0x4024, 0x0000, 0x0200, + 0xb102, 0x0024, 0x0000, 0x00c0, 0x2801, 0x15c5, 0x0005, 0x4f92, 0x2909, + 0xf840, 0x3613, 0x2800, 0x0006, 0x0197, 0x0006, 0xa115, 0xb080, 0x0024, + 0x3f00, 0x3400, 0x0000, 0x190d, 0x000a, 0x708f, 0x280a, 0xc0c0, 0x0000, + 0xd7ce, 0x0000, 0x004d, 0x0020, 0xfe0f, 0x2820, 0xfb40, 0x0001, 0x17ce, + 0x2801, 0x1995, 0x3009, 0x1000, 0x6012, 0x93cc, 0x0000, 0x0024, 0x2801, + 0x3445, 0x0000, 0x0024, 0x3413, 0x0024, 0x34b0, 0x0024, 0x4080, 0x0024, + 0x0000, 0x0200, 0x2801, 0x1c95, 0xb882, 0x0024, 0x3453, 0x0024, 0x3009, + 0x13c0, 0x4080, 0x0024, 0x0000, 0x0200, 0x2801, 0x3445, 0x0000, 0x0024, + 0xb882, 0x130c, 0x0000, 0x004d, 0x0021, 0x058f, 0x2821, 0x0340, 0x0001, + 0x1d8e, 0x2801, 0x2dd5, 0x6012, 0x0024, 0x0000, 0x0024, 0x2801, 0x2dd5, + 0x0000, 0x0024, 0x34c3, 0x184c, 0x3e13, 0xb80f, 0xf400, 0x4500, 0x0026, + 0x9dcf, 0x0001, 0x218e, 0x0000, 0xfa0d, 0x2926, 0x8e80, 0x3e10, 0x110c, + 0x36f3, 0x0024, 0x2801, 0x2dc0, 0x36f3, 0x980f, 0x001c, 0xdd00, 0x001c, + 0xd901, 0x6ec2, 0x0024, 0x001c, 0xdd00, 0x2801, 0x2495, 0x0018, 0xdbc1, + 0x3413, 0x184c, 0xf400, 0x4500, 0x2926, 0xc640, 0x3e00, 0x13cc, 0x2801, + 0x2b80, 0x36f3, 0x0024, 0x6ec2, 0x0024, 0x003f, 0xc000, 0x2801, 0x2715, + 0x002a, 0x4001, 0x3413, 0x184c, 0xf400, 0x4500, 0x2926, 0xafc0, 0x3e00, + 0x13cc, 0x2801, 0x2b80, 0x36f3, 0x0024, 0xb400, 0x0024, 0xd100, 0x0024, + 0x0000, 0x0024, 0x2801, 0x2b85, 0x0000, 0x0024, 0x3613, 0x0024, 0x3e11, + 0x4024, 0x2926, 0x8540, 0x3e01, 0x0024, 0x4080, 0x1b8c, 0x0000, 0x0024, + 0x2801, 0x2b85, 0x0000, 0x0024, 0x3413, 0x184c, 0xf400, 0x4500, 0x2926, + 0x8e80, 0x3e10, 0x13cc, 0x36f3, 0x0024, 0x3110, 0x8024, 0x31f0, 0xc024, + 0x0000, 0x4000, 0x0000, 0x0021, 0x6d06, 0x0024, 0x3110, 0x8024, 0x2826, + 0xa8c4, 0x31f0, 0xc024, 0x2a26, 0xad00, 0x34c3, 0x184c, 0x3410, 0x8024, + 0x3430, 0xc024, 0x0000, 0x4000, 0x0000, 0x0021, 0x6d06, 0x0024, 0x0000, + 0x0024, 0x2801, 0x3454, 0x4d06, 0x0024, 0x0000, 0x0200, 0x2922, 0x1885, + 0x0001, 0x32c8, 0x0000, 0x0200, 0x3e10, 0x8024, 0x2921, 0xca80, 0x3e00, + 0xc024, 0x291a, 0x8a40, 0x0000, 0x0024, 0x2922, 0x1880, 0x36f3, 0x0024, + 0x0000, 0x004d, 0x0021, 0x0ecf, 0x2821, 0x0bc0, 0x0001, 0x33ce, 0x2801, + 0x16c0, 0x3c30, 0x4024, 0x0000, 0x190d, 0x0000, 0x458e, 0x2821, 0x0f80, + 0x0027, 0x9e0f, 0x0020, 0xcd4f, 0x2820, 0xc780, 0x0001, 0x360e, 0x0006, + 0xf017, 0x0000, 0x0015, 0xb070, 0xbc15, 0x0000, 0x458e, 0x0027, 0x9e0f, + 0x2820, 0xcd80, 0x0000, 0x190d, 0x3613, 0x0024, 0x3e10, 0xb803, 0x3e14, + 0x3811, 0x3e11, 0x3805, 0x3e00, 0x3801, 0x0007, 0xc390, 0x0006, 0xa011, + 0x3010, 0x0444, 0x3050, 0x4405, 0x6458, 0x0302, 0xff94, 0x4081, 0x0003, + 0xffc5, 0x48b6, 0x0024, 0xff82, 0x0024, 0x42b2, 0x0042, 0xb458, 0x0003, + 0x4cd6, 0x9801, 0xf248, 0x1bc0, 0xb58a, 0x0024, 0x6de6, 0x1804, 0x0006, + 0x0010, 0x3810, 0x9bc5, 0x3800, 0xc024, 0x36f4, 0x1811, 0x36f0, 0x9803, + 0x283e, 0x2d80, 0x0fff, 0xffc3, 0x2801, 0x4c40, 0x0000, 0x0024, 0x3413, + 0x0024, 0x2801, 0x4045, 0xf400, 0x4517, 0x2801, 0x4440, 0x6894, 0x13cc, + 0x37b0, 0x184c, 0x6090, 0x1d51, 0x0000, 0x0910, 0x3f00, 0x060c, 0x3100, + 0x4024, 0x6016, 0xb812, 0x000c, 0x8012, 0x2801, 0x42d1, 0xb884, 0x0024, + 0x6894, 0x3002, 0x0000, 0x028d, 0x003a, 0x5e0f, 0x0001, 0x544e, 0x2939, + 0xb0c0, 0x3e10, 0x93cc, 0x4084, 0x9bd2, 0x4282, 0x0024, 0x0000, 0x0040, + 0x2801, 0x4645, 0x4292, 0x130c, 0x3443, 0x0024, 0x2801, 0x4785, 0x000c, + 0x8390, 0x2a01, 0x4b00, 0x3444, 0x0024, 0x3073, 0x0024, 0xc090, 0x014c, + 0x2801, 0x4b00, 0x3800, 0x0024, 0x000c, 0x4113, 0xb880, 0x2380, 0x3304, + 0x4024, 0x3800, 0x05cc, 0xcc92, 0x05cc, 0x3910, 0x0024, 0x3910, 0x4024, + 0x000c, 0x8110, 0x3910, 0x0024, 0x39f0, 0x4024, 0x3810, 0x0024, 0x38d0, + 0x4024, 0x3810, 0x0024, 0x38f0, 0x4024, 0x34c3, 0x0024, 0x3444, 0x0024, + 0x3073, 0x0024, 0x3063, 0x0024, 0x3000, 0x0024, 0x4080, 0x0024, 0x0000, + 0x0024, 0x2839, 0x53d5, 0x4284, 0x0024, 0x3613, 0x0024, 0x2801, 0x4e45, + 0x6898, 0xb804, 0x0000, 0x0084, 0x293b, 0x1cc0, 0x3613, 0x0024, 0x000c, + 0x8117, 0x3711, 0x0024, 0x37d1, 0x4024, 0x4e8a, 0x0024, 0x0000, 0x0015, + 0x2801, 0x5105, 0xce9a, 0x0024, 0x3f11, 0x0024, 0x3f01, 0x4024, 0x000c, + 0x8197, 0x408a, 0x9bc4, 0x3f15, 0x4024, 0x2801, 0x5345, 0x4284, 0x3c15, + 0x6590, 0x0024, 0x0000, 0x0024, 0x2839, 0x53d5, 0x4284, 0x0024, 0x0000, + 0x0024, 0x2801, 0x3f18, 0x458a, 0x0024, 0x2a39, 0x53c0, 0x003e, 0x2d4f, + 0x283a, 0x5ed5, 0x0001, 0x37ce, 0x000c, 0x4653, 0x0000, 0x0246, 0xffac, + 0x0c01, 0x48be, 0x0024, 0x4162, 0x4546, 0x6642, 0x4055, 0x3501, 0x8024, + 0x0000, 0x0087, 0x667c, 0x4057, 0x000c, 0x41d5, 0x283a, 0x62d5, 0x3501, + 0x8024, 0x667c, 0x1c47, 0x3701, 0x8024, 0x283a, 0x62d5, 0xc67c, 0x0024, + 0x0000, 0x0024, 0x283a, 0x62c5, 0x0000, 0x0024, 0x2a3a, 0x5ec0, 0x3009, + 0x3851, 0x3e14, 0xf812, 0x3e12, 0xb817, 0x3e11, 0x8024, 0x0006, 0x0293, + 0x3301, 0x8024, 0x468c, 0x3804, 0x0006, 0xa057, 0x2801, 0x6044, 0x0006, + 0x0011, 0x469c, 0x0024, 0x3be1, 0x8024, 0x2801, 0x6055, 0x0006, 0xc392, + 0x3311, 0x0024, 0x33f1, 0x2844, 0x3009, 0x2bc4, 0x0030, 0x04d2, 0x3311, + 0x0024, 0x3a11, 0x0024, 0x3201, 0x8024, 0x003f, 0xfc04, 0xb64c, 0x0fc4, + 0xc648, 0x0024, 0x3a01, 0x0024, 0x3111, 0x1fd3, 0x6498, 0x07c6, 0x868c, + 0x2444, 0x0023, 0xffd2, 0x3901, 0x8e06, 0x0030, 0x0551, 0x3911, 0x8e06, + 0x3961, 0x9c44, 0xf400, 0x44c6, 0xd46c, 0x1bc4, 0x36f1, 0xbc13, 0x2801, + 0x69d5, 0x36f2, 0x9817, 0x002b, 0xffd2, 0x3383, 0x188c, 0x3e01, 0x8c06, + 0x0006, 0xa097, 0x3009, 0x1c12, 0x3213, 0x0024, 0x468c, 0xbc12, 0x002b, + 0xffd2, 0xf400, 0x4197, 0x2801, 0x66c4, 0x3713, 0x0024, 0x2801, 0x6705, + 0x37e3, 0x0024, 0x3009, 0x2c17, 0x3383, 0x0024, 0x3009, 0x0c06, 0x468c, + 0x4197, 0x0006, 0xa052, 0x2801, 0x6904, 0x3713, 0x2813, 0x2801, 0x6945, + 0x37e3, 0x0024, 0x3009, 0x2c17, 0x36f1, 0x8024, 0x36f2, 0x9817, 0x36f4, + 0xd812, 0x2100, 0x0000, 0x3904, 0x5bd1, 0x2a01, 0x5a0e, 0x3e11, 0x7804, + 0x0030, 0x0257, 0x3701, 0x0024, 0x0013, 0x4d05, 0xd45b, 0xe0e1, 0x0007, + 0xc795, 0x2801, 0x7155, 0x0fff, 0xff45, 0x3511, 0x184c, 0x4488, 0xb808, + 0x0006, 0x8a97, 0x2801, 0x7105, 0x3009, 0x1c40, 0x3511, 0x1fc1, 0x0000, + 0x0020, 0xac52, 0x1405, 0x6ce2, 0x0024, 0x0000, 0x0024, 0x2801, 0x7101, + 0x68c2, 0x0024, 0x291a, 0x8a40, 0x3e10, 0x0024, 0x2921, 0xca80, 0x3e00, + 0x4024, 0x36f3, 0x0024, 0x3009, 0x1bc8, 0x36f0, 0x1801, 0x3601, 0x5804, + 0x3e13, 0x780f, 0x3e13, 0xb808, 0x0008, 0x9b0f, 0x0001, 0x740e, 0x2908, + 0x9300, 0x0000, 0x004d, 0x36f3, 0x9808, 0x2000, 0x0000, 0x36f3, 0x580f, + 0x0007, 0x81d7, 0x3711, 0x8024, 0x3711, 0xc024, 0x3700, 0x0024, 0x0000, + 0x2001, 0xb012, 0x0024, 0x0034, 0x0000, 0x2801, 0x7985, 0x0000, 0x01c1, + 0x3700, 0x0024, 0x0002, 0x0001, 0xb012, 0x0024, 0x002e, 0xe001, 0x2801, + 0x7885, 0x6512, 0x0024, 0x0034, 0x0000, 0x2801, 0x7995, 0x0000, 0x01c1, + 0x0030, 0x0117, 0x3f00, 0x0024, 0x0014, 0xc000, 0x0000, 0x01c1, 0x4fce, + 0x0024, 0xffea, 0x0024, 0x48b6, 0x0024, 0x4384, 0x4097, 0xb886, 0x45c6, + 0xfede, 0x0024, 0x4db6, 0x0024, 0x466c, 0x0024, 0x0006, 0xc610, 0x8dd6, + 0x8007, 0x0000, 0x00c6, 0xff6e, 0x0024, 0x48b2, 0x0024, 0x0034, 0x2406, + 0xffee, 0x0024, 0x2914, 0xaa80, 0x40b2, 0x0024, 0xf1c6, 0x0024, 0xf1d6, + 0x0024, 0x0000, 0x0201, 0x8d86, 0x0024, 0x61de, 0x0024, 0x0006, 0xc612, + 0x2801, 0x8001, 0x0006, 0xc713, 0x4c86, 0x0024, 0x2912, 0x1180, 0x0006, + 0xc351, 0x0006, 0x0210, 0x2912, 0x0d00, 0x3810, 0x984c, 0xf200, 0x2043, + 0x2808, 0xa000, 0x3800, 0x0024, 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, + 0x3815, 0x3e05, 0xb814, 0x3635, 0x0024, 0x0000, 0x800a, 0x3e10, 0x7802, + 0x3e14, 0x0024, 0x2900, 0xb740, 0x0000, 0x0201, 0x0000, 0x0601, 0x3413, + 0x184c, 0x2903, 0x7680, 0x3cf0, 0x0024, 0x3413, 0x184c, 0x3400, 0x3040, + 0x3009, 0x33c1, 0x0000, 0x1fc1, 0xb010, 0x0024, 0x6014, 0x9040, 0x0006, + 0x8010, 0x2801, 0x88d5, 0x0000, 0x0024, 0x34e3, 0x1bcc, 0x6890, 0x0024, + 0x2801, 0x8a80, 0xb880, 0x2000, 0x3e10, 0x1381, 0x2903, 0xb8c0, 0x3e00, + 0x4024, 0x003f, 0xfe41, 0x36e3, 0x104c, 0x34f0, 0x0024, 0xa010, 0x0024, + 0x36f4, 0x0024, 0x36f0, 0x5802, 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, + 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, 0x0024, 0x3e12, 0xb817, + 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3615, 0x0024, 0x0000, 0x800a, 0x3e10, + 0xb804, 0x3e01, 0x534c, 0xbe8a, 0x10c0, 0x4080, 0x0024, 0x0000, 0x0024, + 0x2801, 0x93c5, 0x0000, 0x0024, 0x2903, 0x7680, 0x4082, 0x184c, 0x4c8a, + 0x134c, 0x0000, 0x0001, 0x6890, 0x10c2, 0x4294, 0x0024, 0xac22, 0x0024, + 0xbec2, 0x0024, 0x0000, 0x0024, 0x2801, 0x93c5, 0x0000, 0x0024, 0x6890, + 0x134c, 0xb882, 0x10c2, 0xac22, 0x0024, 0x4c92, 0x0024, 0xdc92, 0x0024, + 0xceca, 0x0024, 0x4e82, 0x1bc5, 0x36f0, 0x9804, 0x3405, 0x9014, 0x36f3, + 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, 0x0024, + 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3645, 0x0024, 0x0000, + 0x800a, 0x3e10, 0x3801, 0x3e10, 0xb803, 0x3e11, 0x3805, 0x3e11, 0xb807, + 0x3e14, 0x104c, 0x2900, 0xb740, 0x0000, 0x0081, 0x4080, 0x3040, 0x0000, + 0x0101, 0x2801, 0x9ac5, 0x0000, 0x0024, 0x4090, 0x0024, 0x0006, 0x8050, + 0x2801, 0xaed5, 0x0000, 0x0024, 0x2900, 0xb740, 0x3613, 0x0024, 0xb880, + 0x3000, 0x2801, 0xac80, 0x3009, 0x3380, 0x2900, 0xb740, 0x4122, 0x10cc, + 0x3cf0, 0x0024, 0x3001, 0x0024, 0x3400, 0x0024, 0x6800, 0x0024, 0xa408, + 0x9040, 0x4080, 0x0024, 0x0000, 0x07c1, 0x2801, 0xa055, 0x6894, 0x1380, + 0x6894, 0x130c, 0x3460, 0x0024, 0x6408, 0x4481, 0x4102, 0x1380, 0xf400, + 0x4052, 0x0000, 0x07c1, 0x34f0, 0xc024, 0x6234, 0x0024, 0x6824, 0x0024, + 0xa122, 0x0024, 0x6014, 0x0024, 0x0000, 0x0141, 0x2801, 0xa755, 0x0000, + 0x0024, 0x2900, 0xb740, 0x3613, 0x0024, 0x2801, 0xa5c0, 0xb88a, 0x4002, + 0x2901, 0x8c40, 0x3e00, 0x8024, 0x4c8e, 0xa801, 0x0000, 0x0201, 0x3a10, + 0x1bcc, 0x3000, 0x0024, 0xb010, 0x0024, 0x0000, 0x0024, 0x2801, 0xab55, + 0x659a, 0x0024, 0x6540, 0x184c, 0x0030, 0x0010, 0x2801, 0xa348, 0x0000, + 0x0024, 0x2801, 0xab40, 0x36f3, 0x0024, 0x2801, 0xaa00, 0xb88a, 0x0024, + 0x2903, 0x3ec0, 0x34d0, 0x4024, 0x4c8f, 0xa0a1, 0x0000, 0x0201, 0x3000, + 0x084c, 0xb010, 0x0024, 0x0000, 0x0024, 0x2801, 0xab55, 0x659a, 0x0024, + 0x6540, 0x10cc, 0x0030, 0x0010, 0x2801, 0xa7c8, 0x0000, 0x0024, 0x34d3, + 0x0024, 0x3423, 0x0024, 0xf400, 0x4510, 0x3009, 0x1380, 0x6090, 0x0024, + 0x3009, 0x2000, 0x6892, 0x108c, 0x34f0, 0x9000, 0xa122, 0x984c, 0x6016, + 0x13c1, 0x0000, 0x0102, 0x2801, 0x9c08, 0x0006, 0x8150, 0x2801, 0xaf40, + 0x3009, 0x1bcc, 0x6890, 0x938c, 0x3800, 0x0024, 0x36f4, 0x0024, 0x36f1, + 0x9807, 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f0, 0x1801, 0x3405, 0x9014, + 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, + 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3615, 0x0024, + 0x0000, 0x800a, 0x3e10, 0x3801, 0x3e10, 0xb804, 0x3e11, 0xb807, 0x3e14, + 0x3811, 0x3e04, 0x934c, 0x3430, 0x0024, 0x4080, 0x0024, 0x0000, 0x0206, + 0x2801, 0xb845, 0x0006, 0x8151, 0x3101, 0x130c, 0xff0c, 0x1102, 0x6408, + 0x0024, 0x4204, 0x0024, 0xb882, 0x4092, 0x1005, 0xfe02, 0x48be, 0x0024, + 0x4264, 0x0024, 0x2903, 0xc540, 0xf400, 0x4090, 0x36f4, 0x8024, 0x36f4, + 0x1811, 0x36f1, 0x9807, 0x36f0, 0x9804, 0x36f0, 0x1801, 0x3405, 0x9014, + 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, + 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3675, 0x0024, + 0x3643, 0x0024, 0x0000, 0x800a, 0x3e10, 0x3801, 0x0000, 0x0181, 0x3e10, + 0xb803, 0x3e11, 0x3806, 0x3e11, 0xf810, 0x3e14, 0x7812, 0x3e13, 0xf80e, + 0x2903, 0x47c0, 0x3e03, 0x4024, 0x2900, 0xb740, 0x4088, 0x184c, 0x3413, + 0x184c, 0x2900, 0xb740, 0x6892, 0x3040, 0x4080, 0x3040, 0x0000, 0x0000, + 0x2801, 0xc5c5, 0x0000, 0x0024, 0x6890, 0x0024, 0x2903, 0x47c0, 0x3cd0, + 0x0024, 0x4080, 0x0024, 0x0000, 0x0024, 0x2801, 0xc615, 0x0000, 0x0024, + 0x3433, 0x0024, 0xf400, 0x4510, 0x34d0, 0x0024, 0x6090, 0x0024, 0x2903, + 0x47c0, 0x3800, 0x0024, 0x4080, 0x10cc, 0xf400, 0x4510, 0x2801, 0xc385, + 0x34d0, 0x0024, 0x2801, 0xc600, 0x0000, 0x0024, 0x3cd0, 0x0024, 0x3433, + 0x0024, 0x34a0, 0x0024, 0xf400, 0x4510, 0x3430, 0x4024, 0x6100, 0x0024, + 0x0000, 0x0341, 0x3840, 0x0024, 0x3000, 0x0024, 0x6012, 0x0024, 0x0006, + 0x0581, 0x2801, 0xe381, 0x4012, 0x0024, 0xf400, 0x4057, 0x3702, 0x0024, + 0x2000, 0x0000, 0x0000, 0x0024, 0x34d3, 0x184c, 0x3430, 0x8024, 0x2901, + 0x8c40, 0x3e00, 0x8024, 0x36f3, 0x11cc, 0xb888, 0x104c, 0x3c10, 0x0024, + 0x3c90, 0x4024, 0x2801, 0xcf40, 0x34e3, 0x0024, 0x3411, 0x8024, 0x3491, + 0xc024, 0x4f82, 0x128c, 0x3400, 0x4024, 0x4142, 0x0024, 0xf400, 0x4050, + 0x3800, 0x0024, 0x3440, 0x4024, 0x4142, 0x0024, 0x6498, 0x4050, 0x3009, + 0x2007, 0x0006, 0x8150, 0x3000, 0x11cc, 0x6402, 0x104c, 0x0000, 0x0024, + 0x2801, 0xcc88, 0x0000, 0x0024, 0x3493, 0x0024, 0x2801, 0xff40, 0x34f3, + 0x0024, 0x2801, 0xd6c0, 0xb888, 0x0024, 0x3430, 0x8024, 0x2901, 0x8c40, + 0x3e00, 0x8024, 0x4c8e, 0x130c, 0x3400, 0x5bcc, 0x4142, 0x0024, 0xf400, + 0x4050, 0x3800, 0x0024, 0x3440, 0x4024, 0x4142, 0x0024, 0xf400, 0x4050, + 0x0000, 0x0201, 0x3009, 0x2007, 0x0030, 0x0010, 0x3000, 0x0024, 0xb010, + 0x0024, 0x0000, 0x0024, 0x2801, 0xff55, 0x6498, 0x0024, 0x0006, 0x8150, + 0x3000, 0x134c, 0x6402, 0x984c, 0x0000, 0x0024, 0x2801, 0xd208, 0x0000, + 0x0024, 0x2801, 0xff40, 0x3433, 0x1bcc, 0x0000, 0x0201, 0xb888, 0x104c, + 0x3430, 0x184c, 0x6010, 0x0024, 0x6402, 0x3000, 0x0000, 0x0201, 0x2801, + 0xdf58, 0x0030, 0x0010, 0x4090, 0x124c, 0x2401, 0xde40, 0x0000, 0x0024, + 0x3430, 0x8024, 0x2901, 0x8c40, 0x3e00, 0x8024, 0x4c8e, 0x130c, 0x3400, + 0x4024, 0x4142, 0x0024, 0xf400, 0x4050, 0x3800, 0x0024, 0x3410, 0x4024, + 0x4142, 0x0024, 0x6498, 0x4050, 0x3009, 0x2007, 0x0030, 0x0010, 0x0000, + 0x0201, 0x3473, 0x0024, 0x3490, 0x0024, 0x3e00, 0x13cc, 0x2901, 0x9580, + 0x3444, 0x8024, 0x3000, 0x1bcc, 0xb010, 0x0024, 0x0000, 0x0024, 0x2801, + 0xff55, 0x0000, 0x0024, 0x34c3, 0x184c, 0x3470, 0x0024, 0x3e10, 0x104c, + 0x34c0, 0x4024, 0x2901, 0xb1c0, 0x3e00, 0x4024, 0x2801, 0xff40, 0x36e3, + 0x0024, 0x0000, 0x0801, 0x3413, 0x0024, 0x34f0, 0x0024, 0x6012, 0x0024, + 0x0000, 0x07c1, 0x2801, 0xfe88, 0x0000, 0x0024, 0x6010, 0x114c, 0xb888, + 0x32c0, 0x6402, 0x0024, 0x0000, 0x0101, 0x2801, 0xeb18, 0x0000, 0x0024, + 0x4090, 0x134c, 0x2401, 0xea40, 0x3009, 0x184c, 0x3430, 0x8024, 0x2901, + 0x8c40, 0x3e00, 0x8024, 0x4c8e, 0x130c, 0x3400, 0x4024, 0x4142, 0x0024, + 0xf400, 0x4050, 0x3800, 0x0024, 0x3410, 0x4024, 0x4142, 0x0024, 0x6498, + 0x4050, 0x3009, 0x2007, 0x0000, 0x0101, 0x3433, 0x1bcc, 0x2900, 0xb740, + 0x3613, 0x0024, 0x0000, 0x0141, 0x6090, 0x118c, 0x2900, 0xb740, 0x3ca0, + 0x184c, 0x3473, 0x184c, 0xb888, 0x3380, 0x3400, 0x0024, 0x6402, 0x0024, + 0x0000, 0x0201, 0x2801, 0xf1d8, 0x0000, 0x0024, 0x4090, 0x104c, 0x2401, + 0xf100, 0x0000, 0x0024, 0x34a0, 0x8024, 0x2901, 0x8c40, 0x3e00, 0x8024, + 0x0006, 0x8002, 0x4244, 0x118c, 0x4244, 0x0024, 0x6498, 0x4095, 0x3009, + 0x3440, 0x3009, 0x37c1, 0x0000, 0x0201, 0x34f3, 0x0024, 0x0030, 0x0010, + 0x3490, 0x0024, 0x3e00, 0x138c, 0x2901, 0x9580, 0x3444, 0x8024, 0x3000, + 0x1bcc, 0xb010, 0x0024, 0x0000, 0x0024, 0x2801, 0xff55, 0x4112, 0x0024, + 0x3463, 0x0024, 0x34a0, 0x0024, 0x6012, 0x0024, 0x0006, 0x8111, 0x2801, + 0xfb19, 0x0000, 0x0024, 0x3100, 0x11cc, 0x3490, 0x4024, 0x4010, 0x0024, + 0x0000, 0x0a01, 0x6012, 0x0024, 0x0006, 0x8151, 0x2801, 0xfb18, 0x0000, + 0x0024, 0x3613, 0x114c, 0x3101, 0x3804, 0x3490, 0x8024, 0x6428, 0x138c, + 0x3470, 0x8024, 0x3423, 0x0024, 0x3420, 0xc024, 0x4234, 0x1241, 0x4380, + 0x4092, 0x2903, 0xc540, 0x0006, 0x8010, 0x2801, 0xff40, 0x3009, 0x1bcc, + 0x0006, 0x8151, 0x3613, 0x114c, 0x3101, 0x3804, 0x3490, 0x8024, 0x6428, + 0x138c, 0x3470, 0x8024, 0x3423, 0x0024, 0x3420, 0xc024, 0x4234, 0x1241, + 0x4380, 0x4092, 0x2903, 0xcf00, 0x0006, 0x8010, 0x2801, 0xff40, 0x3009, + 0x1bcc, 0x0006, 0x8050, 0x6890, 0x0024, 0x3800, 0x0024, 0x3433, 0x0024, + 0x34d0, 0x0024, 0x4080, 0x0024, 0x0006, 0x8150, 0x2802, 0x04c5, 0x0000, + 0x0024, 0x3000, 0x11cc, 0xb888, 0x10cc, 0x6402, 0x3240, 0x3493, 0x0024, + 0x3444, 0x8024, 0x2802, 0x04d8, 0x4090, 0x0024, 0x2402, 0x0480, 0x0000, + 0x0024, 0x6499, 0x2620, 0xb78e, 0x4001, 0x0000, 0x0000, 0x3433, 0x0024, + 0xcfce, 0x1340, 0xaf0e, 0x0024, 0x3a11, 0xa807, 0x36f3, 0x4024, 0x36f3, + 0xd80e, 0x36f4, 0x5812, 0x36f1, 0xd810, 0x36f1, 0x1806, 0x36f0, 0x9803, + 0x36f0, 0x1801, 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, + 0x0000, 0x36f2, 0x9817, 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, + 0x3e05, 0xb814, 0x3615, 0x0024, 0x0000, 0x800a, 0x3e10, 0x7802, 0x3e10, + 0xf804, 0x0000, 0x3fc3, 0x3e11, 0x7806, 0x3e11, 0xf810, 0xbc82, 0x12cc, + 0x3404, 0x0024, 0x3023, 0x0024, 0x3810, 0x0024, 0x38f0, 0x4024, 0x3454, + 0x0024, 0x3810, 0x0024, 0x38f0, 0x4024, 0x2900, 0xb740, 0x0000, 0x0201, + 0x0006, 0x9301, 0x4088, 0x134c, 0x3400, 0x8024, 0xd204, 0x0024, 0xb234, + 0x0024, 0x4122, 0x0024, 0xf400, 0x4055, 0x3500, 0x0024, 0x3c30, 0x0024, + 0x0000, 0x2000, 0xb400, 0x0024, 0x0000, 0x3001, 0x2802, 0x1255, 0x0000, + 0x3800, 0x0000, 0x0041, 0xfe42, 0x12cc, 0x48b2, 0x1090, 0x3810, 0x0024, + 0x38f0, 0x4024, 0x2802, 0x3340, 0x3430, 0x0024, 0xb400, 0x0024, 0x6012, + 0x0024, 0x0000, 0x3801, 0x2802, 0x1595, 0x0000, 0x3c00, 0x0000, 0x07c0, + 0x0000, 0x0041, 0xb400, 0x12cc, 0xfe02, 0x1150, 0x48b2, 0x0024, 0x689a, + 0x2040, 0x2802, 0x3200, 0x38f0, 0x4024, 0xb400, 0x0024, 0x6012, 0x0024, + 0x0000, 0x3c01, 0x2802, 0x1915, 0x0000, 0x3e00, 0x0000, 0x03c0, 0x0000, + 0x0085, 0x4592, 0x12cc, 0xb400, 0x1150, 0xfe02, 0x0024, 0x48b2, 0x0024, + 0x3810, 0x0024, 0x2802, 0x3200, 0x38f0, 0x4024, 0xb400, 0x0024, 0x6012, + 0x0024, 0x0000, 0x3e01, 0x2802, 0x1c95, 0x0000, 0x3f00, 0x0000, 0x01c0, + 0xf20a, 0x12cc, 0xb400, 0x1150, 0xf252, 0x0024, 0xfe02, 0x0024, 0x48b2, + 0x0024, 0x3810, 0x0024, 0x2802, 0x3200, 0x38f0, 0x4024, 0xb400, 0x130c, + 0x6012, 0x0024, 0x0000, 0x3f01, 0x2802, 0x2015, 0x4390, 0x0024, 0x0000, + 0x0041, 0x0000, 0x0105, 0x4590, 0x13cc, 0xb400, 0x1150, 0xfe02, 0x0024, + 0x48b2, 0x0024, 0x3810, 0x0024, 0x2802, 0x3200, 0x38f0, 0x4024, 0xb400, + 0x0024, 0x6012, 0x1100, 0x0000, 0x01c1, 0x2802, 0x2395, 0x0000, 0x0024, + 0x0000, 0x0041, 0x0000, 0x0145, 0x6890, 0x12cc, 0xb400, 0x1150, 0xfe02, + 0x0024, 0x48b2, 0x0024, 0x3810, 0x0024, 0x2802, 0x3200, 0x38f0, 0x4024, + 0x6012, 0x0024, 0x0000, 0x3f81, 0x2802, 0x2615, 0xb430, 0x0024, 0x6012, + 0x0024, 0x0000, 0x0024, 0x2802, 0x2615, 0x0000, 0x0024, 0x2802, 0x3200, + 0x0000, 0x0185, 0x2802, 0x3340, 0xc890, 0x0024, 0x0000, 0x3fc3, 0x0000, + 0x0201, 0x34d3, 0x0024, 0x2900, 0xb740, 0x3433, 0x184c, 0x0006, 0x9301, + 0x4088, 0x134c, 0x3400, 0x8024, 0xd204, 0x0024, 0xb234, 0x0024, 0x4122, + 0x0024, 0xf400, 0x4055, 0x0000, 0x2001, 0x3500, 0x0024, 0x3c30, 0x0024, + 0x0000, 0x3000, 0xb400, 0x0024, 0x6012, 0x0024, 0x0000, 0x0182, 0x2802, + 0x2c45, 0x0000, 0x0024, 0x2802, 0x3340, 0xc890, 0x0024, 0x459a, 0x12cc, + 0x3404, 0x0024, 0x3023, 0x0024, 0x3010, 0x0024, 0x30d0, 0x4024, 0xac22, + 0x0046, 0x003f, 0xf982, 0x3011, 0xc024, 0x0000, 0x0023, 0xaf2e, 0x0024, + 0x0000, 0x0182, 0xccf2, 0x0024, 0x0000, 0x0fc6, 0x0000, 0x0047, 0xb46c, + 0x2040, 0xfe6e, 0x23c1, 0x3454, 0x0024, 0x3010, 0x0024, 0x30f0, 0x4024, + 0xac22, 0x0024, 0xccb2, 0x0024, 0x3810, 0x0024, 0x38f0, 0x4024, 0x458a, + 0x134c, 0x0000, 0x0201, 0x2802, 0x2755, 0x0000, 0x3fc3, 0x3430, 0x0024, + 0x36f1, 0xd810, 0x36f1, 0x5806, 0x36f0, 0xd804, 0x36f0, 0x5802, 0x3405, + 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, + 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3675, + 0x0024, 0x3633, 0x0024, 0x0000, 0x800a, 0x3e10, 0x3801, 0x3e10, 0xb803, + 0x3e11, 0x3805, 0x3e11, 0xb807, 0x3e14, 0x3811, 0x3e14, 0xb813, 0x3e13, + 0xf80e, 0x3e03, 0x4024, 0x2903, 0xac40, 0x0000, 0x0381, 0x000f, 0xff81, + 0x6012, 0x184c, 0x0000, 0x0201, 0x2802, 0x3bc5, 0x0000, 0x0024, 0x2900, + 0xb740, 0x0003, 0x1f08, 0x3613, 0x0024, 0x0000, 0x0401, 0x0006, 0x8a10, + 0x2900, 0xbf40, 0xb880, 0x1bcc, 0xb880, 0x11cc, 0x3413, 0x184c, 0x3c90, + 0x0024, 0x2900, 0xb740, 0x34f3, 0x0024, 0x3473, 0x184c, 0x3c00, 0x0000, + 0x4080, 0x0024, 0x0006, 0x9301, 0x2802, 0x4145, 0x003f, 0xfe04, 0x3490, + 0x8024, 0xa244, 0x0024, 0x2903, 0x8f40, 0xb880, 0x0024, 0x2900, 0xbf40, + 0x003f, 0xfe04, 0x3473, 0x184c, 0x0006, 0x8091, 0x3413, 0x0024, 0x34f0, + 0x8024, 0x3400, 0xc024, 0xa346, 0x0024, 0xd234, 0x0024, 0x0000, 0x3fc3, + 0xb234, 0x0024, 0x4122, 0x1042, 0xf400, 0x4055, 0x0006, 0x9301, 0x3500, + 0x0024, 0xd024, 0x3000, 0xb234, 0x0024, 0x4122, 0x0024, 0x6892, 0x4055, + 0x3500, 0x0024, 0x3cf0, 0x0024, 0x34a0, 0x0024, 0xf100, 0x0024, 0xb010, + 0x0024, 0x3c60, 0x0024, 0x34b0, 0x0024, 0xb010, 0x0024, 0x0000, 0x0201, + 0x2900, 0xb740, 0x3ce0, 0x0024, 0x0006, 0x9301, 0x3473, 0x184c, 0x3c10, + 0x0024, 0x34f0, 0x8024, 0x3410, 0xc024, 0xd234, 0x0024, 0x0000, 0x3fc3, + 0xb234, 0x0024, 0x4122, 0x0024, 0xf400, 0x4055, 0x003f, 0xff01, 0x3500, + 0x0024, 0x3cf0, 0x0024, 0x34c0, 0x0024, 0xa010, 0x0024, 0x0000, 0x03c1, + 0x3c40, 0x0024, 0x34d0, 0x0024, 0xb010, 0x0024, 0x0000, 0x0201, 0x2900, + 0xb740, 0x3cc0, 0x0024, 0x0006, 0x9301, 0x3473, 0x0024, 0x3c10, 0x0024, + 0x34f0, 0x8024, 0x3410, 0xc024, 0xd234, 0x0024, 0x0000, 0x3fc3, 0xb234, + 0x0024, 0x4122, 0x0024, 0xf400, 0x4055, 0x003f, 0xff01, 0x3500, 0x0024, + 0x3cf0, 0x0024, 0x3400, 0x0024, 0xa010, 0x0024, 0x0000, 0x01c1, 0x3900, + 0x0024, 0x34e0, 0x0024, 0xf100, 0x0024, 0xb010, 0x0024, 0x6892, 0x3080, + 0x34f0, 0x0024, 0xb010, 0x0024, 0x3cb0, 0x0024, 0x3450, 0x0024, 0x34a0, + 0x4024, 0xc010, 0x0024, 0x0000, 0x0181, 0x2802, 0x55c5, 0x3100, 0x0024, + 0x6890, 0x07cc, 0x2803, 0x1f00, 0x3900, 0x0024, 0x6012, 0x0024, 0x0000, + 0x0201, 0x2802, 0x5758, 0x0000, 0x0024, 0x2802, 0x5a40, 0x6090, 0x044c, + 0x6012, 0x0024, 0x0000, 0x0281, 0x2802, 0x5988, 0x6012, 0x0024, 0x0000, + 0x0080, 0x2802, 0x5999, 0x0000, 0x0024, 0x2802, 0x5a40, 0x3113, 0x0024, + 0x6890, 0x07cc, 0x2803, 0x1f00, 0x3900, 0x0024, 0x0000, 0x0201, 0x3900, + 0x114c, 0x34b0, 0x0024, 0x6012, 0x0024, 0x0006, 0x08c1, 0x2802, 0x6481, + 0x4012, 0x0024, 0xf400, 0x4057, 0x3702, 0x0024, 0x2000, 0x0000, 0x0000, + 0x0024, 0x2802, 0x6480, 0x0000, 0x0024, 0x0000, 0x0200, 0x0006, 0x8110, + 0x2802, 0x6480, 0x3800, 0x0024, 0x0000, 0x0300, 0x0006, 0x8110, 0x2802, + 0x6480, 0x3800, 0x0024, 0x0006, 0x8050, 0x6890, 0x0024, 0x2803, 0x1f00, + 0x3800, 0x0024, 0x0000, 0x0400, 0x0006, 0x8110, 0x2802, 0x6480, 0x3800, + 0x0024, 0x0000, 0x0500, 0x0006, 0x8110, 0x2802, 0x6480, 0x3800, 0x0024, + 0x0000, 0x0600, 0x0006, 0x8110, 0x2802, 0x6480, 0x3800, 0x0024, 0x0006, + 0x8050, 0x6890, 0x0024, 0x2803, 0x1f00, 0x3800, 0x0024, 0x3423, 0x184c, + 0x3460, 0x0024, 0x4080, 0x0024, 0x0006, 0x8200, 0x2802, 0x69c5, 0x3e10, + 0x0024, 0x0000, 0x01c0, 0x3e10, 0x0024, 0x3490, 0x0024, 0x2902, 0x07c0, + 0x3e00, 0x13cc, 0x36d3, 0x11cc, 0x3413, 0x0024, 0x4080, 0x3240, 0x34f3, + 0x0024, 0x2802, 0x6d98, 0x0000, 0x0024, 0x0006, 0x8010, 0x6890, 0x0024, + 0x2803, 0x1f00, 0x3800, 0x0024, 0x0000, 0x0180, 0x3e10, 0x0024, 0x3490, + 0x0024, 0x2902, 0x07c0, 0x3e00, 0x13cc, 0x36d3, 0x11cc, 0x3413, 0x0024, + 0x4080, 0x3240, 0x34f3, 0x0024, 0x2802, 0x6d98, 0x0000, 0x0024, 0x0006, + 0x8010, 0x6890, 0x0024, 0x2803, 0x1f00, 0x3800, 0x0024, 0x0000, 0x0201, + 0x3433, 0x0024, 0x34d0, 0x0024, 0x6012, 0x0024, 0x0006, 0x0ac1, 0x2802, + 0x7f81, 0x4012, 0x0024, 0xf400, 0x4057, 0x3702, 0x0024, 0x2000, 0x0000, + 0x0000, 0x0024, 0x0006, 0x8050, 0x6890, 0x0024, 0x2803, 0x1f00, 0x3800, + 0x0024, 0x0000, 0x3000, 0x2802, 0x8140, 0x0006, 0x8150, 0x0000, 0x9000, + 0x0006, 0x8150, 0x3433, 0x0024, 0x34d0, 0x4024, 0x4192, 0x0024, 0x4192, + 0x0024, 0x2802, 0x8140, 0xa010, 0x0024, 0x0000, 0x0201, 0x0006, 0x8150, + 0x2900, 0xb740, 0x3613, 0x0024, 0x0006, 0x9301, 0x3473, 0x0024, 0x3c10, + 0x0024, 0x34f0, 0x8024, 0x3410, 0xc024, 0xd234, 0x0024, 0x0000, 0x3fc3, + 0xb234, 0x0024, 0x4122, 0x0024, 0xf400, 0x4055, 0x3500, 0x0024, 0x3cf0, + 0x0024, 0x3490, 0x0024, 0x2802, 0x8140, 0x6090, 0x0024, 0x003f, 0xfe04, + 0x0000, 0x0401, 0x0006, 0x8150, 0x2900, 0xb740, 0x3613, 0x0024, 0x0006, + 0x9301, 0x3473, 0x0024, 0x3c10, 0x0024, 0x34f0, 0x8024, 0x3400, 0xc024, + 0xa346, 0x0024, 0xd234, 0x0024, 0x0000, 0x3fc3, 0xb234, 0x0024, 0x4122, + 0x1042, 0xf400, 0x4055, 0x0006, 0x9301, 0x3500, 0x0024, 0xd024, 0x3000, + 0xb234, 0x0024, 0x4122, 0x0024, 0xf400, 0x4055, 0x3500, 0x0024, 0x3cf0, + 0x0024, 0x3490, 0x0024, 0x2802, 0x8140, 0x6090, 0x0024, 0x0000, 0x4000, + 0x0000, 0x0202, 0x0006, 0x8150, 0x3433, 0x0024, 0x34d0, 0x4024, 0x6122, + 0x0024, 0xa010, 0x0024, 0x0004, 0x8001, 0x3800, 0x110c, 0x0006, 0x8150, + 0x3000, 0x0024, 0x6012, 0x1300, 0x0000, 0x0401, 0x2802, 0x8409, 0x0000, + 0x0024, 0x6890, 0x82cc, 0x2803, 0x1f00, 0x3800, 0x0024, 0x6012, 0x0024, + 0x0006, 0x0cc1, 0x2802, 0xab81, 0x4012, 0x0024, 0xf400, 0x4057, 0x3702, + 0x0024, 0x2000, 0x0000, 0x0000, 0x0024, 0x2802, 0xab80, 0x0000, 0x0024, + 0x0016, 0x2200, 0x0006, 0x8190, 0x6892, 0x2040, 0x2802, 0xab80, 0x38f0, + 0x4024, 0x002c, 0x4400, 0x0000, 0x0081, 0x0006, 0x8190, 0x3810, 0x0024, + 0x2802, 0xab80, 0x38f0, 0x4024, 0x003b, 0x8000, 0x0000, 0x0081, 0x0006, + 0x8190, 0x3810, 0x0024, 0x2802, 0xab80, 0x38f0, 0x4024, 0x0007, 0xd000, + 0x0006, 0x8190, 0xb882, 0x2040, 0x2802, 0xab80, 0x38f0, 0x4024, 0x000f, + 0xa000, 0x0006, 0x8190, 0xb882, 0x2040, 0x2802, 0xab80, 0x38f0, 0x4024, + 0x0015, 0x8880, 0x0006, 0x8190, 0xb882, 0x2040, 0x2802, 0xab80, 0x38f0, + 0x4024, 0x0017, 0x7000, 0x0006, 0x8190, 0xb882, 0x2040, 0x2802, 0xab80, + 0x38f0, 0x4024, 0x001f, 0x4000, 0x0006, 0x8190, 0xb882, 0x2040, 0x2802, + 0xab80, 0x38f0, 0x4024, 0x002b, 0x1100, 0x0006, 0x8190, 0xb882, 0x2040, + 0x2802, 0xab80, 0x38f0, 0x4024, 0x002e, 0xe000, 0x0006, 0x8190, 0xb882, + 0x2040, 0x2802, 0xab80, 0x38f0, 0x4024, 0x001d, 0xc000, 0x0006, 0x8190, + 0x6892, 0x2040, 0x2802, 0xab80, 0x38f0, 0x4024, 0x0006, 0x8190, 0x0000, + 0x0201, 0x0000, 0xfa04, 0x2900, 0xb740, 0x3613, 0x0024, 0x0006, 0x9301, + 0xb88a, 0x11cc, 0x3c10, 0x0024, 0x34f0, 0x8024, 0x3410, 0xc024, 0xd234, + 0x0024, 0x0000, 0x3fc3, 0xb234, 0x0024, 0x4122, 0x0024, 0xf400, 0x4055, + 0x3500, 0x0024, 0x3cf0, 0x0024, 0x3490, 0x0024, 0xfe50, 0x4005, 0x48b2, + 0x0024, 0xfeca, 0x0024, 0x40b2, 0x0024, 0x3810, 0x0024, 0x2802, 0xab80, + 0x38f0, 0x4024, 0x003f, 0xfe04, 0x0000, 0x0401, 0x0006, 0x8190, 0x2900, + 0xb740, 0x3613, 0x0024, 0x0006, 0x9301, 0x3473, 0x0024, 0x3c10, 0x0024, + 0x34f0, 0x8024, 0x3400, 0xc024, 0xa346, 0x0024, 0xd234, 0x0024, 0x0000, + 0x3fc3, 0xb234, 0x0024, 0x4122, 0x1042, 0xf400, 0x4055, 0x0006, 0x9301, + 0x3500, 0x0024, 0xd024, 0x3000, 0xb234, 0x0024, 0x4122, 0x0024, 0xf400, + 0x4055, 0x0000, 0x0041, 0x3500, 0x0024, 0x3cf0, 0x0024, 0x3490, 0x0024, + 0xfe02, 0x0024, 0x48b2, 0x0024, 0x3810, 0x0024, 0x2802, 0xab80, 0x38f0, + 0x4024, 0x003f, 0xfe04, 0x0000, 0x0401, 0x0006, 0x8190, 0x2900, 0xb740, + 0x3613, 0x0024, 0x0006, 0x9301, 0x3473, 0x0024, 0x3c10, 0x0024, 0x34f0, + 0x8024, 0x3400, 0xc024, 0xa346, 0x0024, 0xd234, 0x0024, 0x0000, 0x3fc3, + 0xb234, 0x0024, 0x4122, 0x1042, 0xf400, 0x4055, 0x0006, 0x9301, 0x3500, + 0x0024, 0xd024, 0x3000, 0xb234, 0x0024, 0x4122, 0x0024, 0xf400, 0x4055, + 0x3500, 0x0024, 0x3cf0, 0x0024, 0x0000, 0x0280, 0x3490, 0x4024, 0xfe02, + 0x0024, 0x48b2, 0x0024, 0x3810, 0x0024, 0x2802, 0xab80, 0x38f0, 0x4024, + 0x0006, 0x8010, 0x6890, 0x0024, 0x2803, 0x1f00, 0x3800, 0x0024, 0x0000, + 0x0201, 0x2900, 0xb740, 0x3613, 0x11cc, 0x3c10, 0x0024, 0x3490, 0x4024, + 0x6014, 0x13cc, 0x0000, 0x0081, 0x2802, 0xaec5, 0x0006, 0x80d0, 0x0006, + 0x8010, 0x6890, 0x0024, 0x2803, 0x1f00, 0x3800, 0x0024, 0x3010, 0x0024, + 0x6012, 0x0024, 0x0000, 0x0241, 0x2802, 0xce49, 0x0006, 0x8112, 0x0008, + 0x0001, 0x3009, 0x184c, 0x3e10, 0x4024, 0x3000, 0x8024, 0x2901, 0xbac0, + 0x3e00, 0x8024, 0x36f3, 0x004c, 0x3000, 0x3844, 0x0008, 0x0010, 0xb884, + 0x3840, 0x0000, 0x0400, 0x3e00, 0x8024, 0x3201, 0x0024, 0x2903, 0x5680, + 0x6408, 0x4091, 0x0001, 0x0000, 0x000b, 0x8011, 0x0004, 0x0010, 0x36e3, + 0x0024, 0x2915, 0x8300, 0x3009, 0x1bc4, 0x000b, 0x8000, 0x3613, 0x0024, + 0x3e10, 0x0024, 0x3200, 0xc024, 0x2901, 0xbac0, 0x3e00, 0xc024, 0x36f3, + 0x084c, 0x32f0, 0xf844, 0x3e10, 0xc024, 0x3e00, 0x8024, 0x2b01, 0x0091, + 0x0000, 0x0400, 0xf204, 0x0804, 0x2903, 0x5680, 0x6408, 0x0024, 0x000b, + 0x8011, 0x0008, 0x0010, 0x0000, 0x0084, 0x36d3, 0x0024, 0x2915, 0x8300, + 0x0003, 0x8000, 0x0005, 0x0010, 0x0001, 0x0000, 0x2915, 0x8300, 0x000f, + 0x0011, 0x1006, 0x0ac0, 0x32f3, 0x11cc, 0x3200, 0xd08c, 0xff34, 0x0024, + 0x48b6, 0x0024, 0x4020, 0x0024, 0x3c90, 0x0024, 0x2802, 0xca80, 0x34e3, + 0x0024, 0x0006, 0x8112, 0x3613, 0x0024, 0x3e10, 0x0024, 0x3000, 0x4024, + 0x2901, 0xbac0, 0x3e00, 0x4024, 0x36f3, 0x004c, 0x3000, 0x7844, 0xb884, + 0x3841, 0x2b01, 0x0091, 0x0000, 0x0400, 0x3e00, 0x8024, 0x3201, 0x0024, + 0x2903, 0x5680, 0x6408, 0x0024, 0x0003, 0x8000, 0x000b, 0x8011, 0x0008, + 0x0010, 0x36e3, 0x11cc, 0x3423, 0x0024, 0x3494, 0xc024, 0x2903, 0x7ac0, + 0x3301, 0x138c, 0x0001, 0x0000, 0x000f, 0x0011, 0x0004, 0x0010, 0x2903, + 0x8000, 0x3301, 0x0024, 0xf400, 0x4510, 0x000b, 0x8011, 0x3073, 0x0024, + 0x3023, 0x0024, 0x3000, 0x0024, 0x6090, 0x0024, 0x3800, 0x0024, 0x0003, + 0x8000, 0x3004, 0xc024, 0x0008, 0x0010, 0x2903, 0x8000, 0x3301, 0x0024, + 0x0001, 0x0000, 0x000f, 0x0011, 0x0005, 0x0010, 0x2903, 0x8000, 0x3301, + 0x0024, 0xf400, 0x4510, 0x3073, 0x1bc4, 0x6498, 0x008c, 0x3000, 0x0024, + 0x6090, 0x0024, 0x3800, 0x0024, 0x0006, 0x80d0, 0x3000, 0x0024, 0x6402, + 0x0024, 0x0006, 0x8110, 0x2802, 0xbdc8, 0x000b, 0x8000, 0x000b, 0x8010, + 0x0001, 0x0000, 0x2903, 0xe0c0, 0x0004, 0x0011, 0x0005, 0x0011, 0x000b, + 0x8010, 0x0001, 0x0000, 0x291f, 0xc6c0, 0x0002, 0xdf88, 0x30e1, 0x184c, + 0x3000, 0x0024, 0x6012, 0x0024, 0x0008, 0x0001, 0x2802, 0xd015, 0x0000, + 0x0024, 0x6498, 0x0024, 0x3e10, 0x4024, 0x0000, 0x0081, 0x2901, 0xbac0, + 0x3e01, 0x0024, 0x36e3, 0x004c, 0x3000, 0x0024, 0x6012, 0x0024, 0x000b, + 0x8011, 0x2802, 0xdc55, 0x0006, 0x8112, 0x0000, 0x0201, 0x0004, 0x0010, + 0x2915, 0x8300, 0x0001, 0x0000, 0x000b, 0x8011, 0x0005, 0x0010, 0x291f, + 0xc6c0, 0x0001, 0x0000, 0x0006, 0x8110, 0x30e1, 0x0024, 0x3000, 0x0024, + 0x6012, 0x0024, 0x0000, 0x0281, 0x2802, 0xd745, 0x6012, 0x0024, 0x000b, + 0x8001, 0x2802, 0xd7d5, 0x3613, 0x0024, 0x36f3, 0x0024, 0x000b, 0x8001, + 0x6498, 0x184c, 0x0006, 0x8112, 0x0003, 0x8000, 0x3e10, 0x4024, 0x2901, + 0xbac0, 0x3e01, 0x0024, 0x36f3, 0x0024, 0x3009, 0x3844, 0x3e10, 0x0024, + 0x0000, 0x0400, 0x3000, 0x8024, 0x0008, 0x0010, 0x3e00, 0x8024, 0x3201, + 0x0024, 0x2903, 0x5680, 0x6408, 0x4051, 0x36e3, 0x0024, 0x2802, 0xdf80, + 0x3009, 0x1bc4, 0x0000, 0x0400, 0x0000, 0x0011, 0x3613, 0x008c, 0x30d0, + 0x7844, 0x3e10, 0x4024, 0x3000, 0x8024, 0x0008, 0x0010, 0x3e00, 0x8024, + 0x3201, 0x0024, 0x2903, 0x5680, 0x6408, 0x0024, 0x36e3, 0x0024, 0x3009, + 0x1bc4, 0x0006, 0x8a10, 0x0000, 0x01c1, 0x3009, 0x0000, 0xb010, 0x0024, + 0x0000, 0x0024, 0x2802, 0xe385, 0x6192, 0x0024, 0x2900, 0xb740, 0x6102, + 0x184c, 0x4088, 0x0024, 0x0000, 0x0024, 0x2802, 0xe385, 0x0000, 0x0024, + 0x0006, 0x8051, 0x6890, 0x0024, 0x3900, 0x0024, 0x3009, 0x0000, 0x4080, + 0x0024, 0x0000, 0x0024, 0x2903, 0x8e85, 0x0002, 0xe848, 0x0006, 0x9f92, + 0x0000, 0x4003, 0x3009, 0x0811, 0x3100, 0x8024, 0xffa6, 0x0024, 0x48b6, + 0x0024, 0x2903, 0x8e80, 0x4384, 0x0024, 0x2903, 0x8f40, 0x3613, 0x0024, + 0x2900, 0xbf40, 0x0000, 0x0024, 0x2903, 0x8e80, 0x0000, 0x0024, 0x0000, + 0x0401, 0x3473, 0x184c, 0x2900, 0xb740, 0x3c10, 0x0024, 0x3c90, 0x0024, + 0x290b, 0x1400, 0x34f3, 0x0024, 0x4080, 0x0024, 0x0000, 0x0024, 0x2803, + 0x1b95, 0x0000, 0x0024, 0x3473, 0x0024, 0x3410, 0x0024, 0x34a0, 0x4024, + 0x6014, 0x1380, 0x0000, 0x0024, 0x2802, 0xf045, 0x4080, 0x0024, 0x0006, + 0x8011, 0x6890, 0x0024, 0xb882, 0x2400, 0x0004, 0x8000, 0x2914, 0xbec0, + 0x0008, 0x0010, 0x0000, 0x0400, 0x3143, 0x108c, 0x6890, 0x27c0, 0x3920, + 0x0024, 0x0004, 0x8000, 0x3900, 0x0024, 0x34e0, 0x0024, 0x4080, 0x0024, + 0x0006, 0x8150, 0x2802, 0xf445, 0x0000, 0x3200, 0x0000, 0x0142, 0x0006, + 0x8210, 0x3613, 0x0024, 0x3e00, 0x7800, 0x3011, 0x8024, 0x30d1, 0xc024, + 0xfef4, 0x4087, 0x48b6, 0x0040, 0xfeee, 0x03c1, 0x2914, 0xa580, 0x42b6, + 0x0024, 0x2802, 0xf840, 0x0007, 0x89d0, 0x0000, 0x0142, 0x3613, 0x0024, + 0x3e00, 0x7800, 0x3031, 0x8024, 0x3010, 0x0024, 0x30d0, 0x4024, 0xfe9c, + 0x4181, 0x48be, 0x0024, 0xfe82, 0x0040, 0x46be, 0x03c1, 0xfef4, 0x4087, + 0x48b6, 0x0024, 0xfeee, 0x0024, 0x2914, 0xa580, 0x42b6, 0x0024, 0x0007, + 0x89d0, 0x0006, 0x8191, 0x4c8a, 0x9800, 0xfed0, 0x4005, 0x48b2, 0x0024, + 0xfeca, 0x0024, 0x40b2, 0x0024, 0x3810, 0x0024, 0x38f0, 0x4024, 0x3111, + 0x8024, 0x468a, 0x0707, 0x2908, 0xbe80, 0x3101, 0x0024, 0x3123, 0x11cc, + 0x3100, 0x108c, 0x3009, 0x3000, 0x0004, 0x8000, 0x3009, 0x1241, 0x6014, + 0x138c, 0x000b, 0x8011, 0x2802, 0xfe81, 0x0000, 0x0024, 0x3473, 0x0024, + 0x3423, 0x0024, 0x3009, 0x3240, 0x34e3, 0x0024, 0x2803, 0x19c0, 0x0008, + 0x0012, 0x0000, 0x0081, 0x2803, 0x0009, 0x0006, 0x80d0, 0xf400, 0x4004, + 0x3000, 0x0024, 0x6012, 0x0024, 0x0000, 0x0005, 0x2803, 0x0589, 0x0000, + 0x0024, 0x6540, 0x0024, 0x0000, 0x0024, 0x2803, 0x15d8, 0x4490, 0x0024, + 0x2403, 0x04c0, 0x0000, 0x0024, 0x0006, 0x8301, 0x4554, 0x0800, 0x4122, + 0x0024, 0x659a, 0x4055, 0x0006, 0x8341, 0x3d00, 0x0840, 0x4122, 0x0024, + 0xf400, 0x4055, 0x3d00, 0x0024, 0x2803, 0x15c0, 0x0000, 0x0024, 0x4090, + 0x0024, 0xf400, 0x4480, 0x2803, 0x0ad5, 0x000b, 0x8001, 0x6540, 0x0024, + 0x0000, 0x0024, 0x2803, 0x15d8, 0x4490, 0x0024, 0x2403, 0x0a00, 0x0000, + 0x0024, 0x0006, 0x8301, 0x4554, 0x0800, 0x4122, 0x0024, 0x659a, 0x4055, + 0x0006, 0x8341, 0x4122, 0x3400, 0xf400, 0x4055, 0x3210, 0x0024, 0x3d00, + 0x0024, 0x2803, 0x15c0, 0x0000, 0x0024, 0x6014, 0x0024, 0x0001, 0x0000, + 0x2803, 0x1215, 0x0003, 0x8001, 0x0008, 0x0012, 0x0008, 0x0010, 0x0006, + 0x8153, 0x3613, 0x0024, 0x3009, 0x3811, 0x2903, 0xe0c0, 0x0004, 0x0011, + 0x0008, 0x0010, 0x0001, 0x0000, 0x291f, 0xc6c0, 0x0005, 0x0011, 0x000f, + 0x0011, 0x0008, 0x0010, 0x33d0, 0x184c, 0x6010, 0xb844, 0x3e10, 0x0024, + 0x0000, 0x0400, 0x3320, 0x4024, 0x3e00, 0x4024, 0x3301, 0x0024, 0x2903, + 0x5680, 0x6408, 0x0024, 0x36e3, 0x0024, 0x3009, 0x1bc4, 0x3009, 0x1bd1, + 0x6540, 0x0024, 0x0000, 0x0024, 0x2803, 0x15d8, 0x4490, 0x0024, 0x2403, + 0x1580, 0x0000, 0x0024, 0x0006, 0x8301, 0x4554, 0x0840, 0x4122, 0x0024, + 0x659a, 0x4055, 0x0006, 0x8341, 0x4122, 0x3400, 0xf400, 0x4055, 0x3110, + 0x0024, 0x3d00, 0x0024, 0xf400, 0x4510, 0x0030, 0x0013, 0x3073, 0x184c, + 0x3e11, 0x008c, 0x3009, 0x0001, 0x6140, 0x0024, 0x0000, 0x0201, 0x3009, + 0x2000, 0x0006, 0x8300, 0x290c, 0x7300, 0x3e10, 0x0024, 0x3300, 0x1b8c, + 0xb010, 0x0024, 0x0000, 0x0024, 0x2803, 0x1b95, 0x0000, 0x0024, 0x3473, + 0x0024, 0x3423, 0x0024, 0x3009, 0x1240, 0x4080, 0x138c, 0x0000, 0x0804, + 0x2802, 0xff15, 0x6402, 0x0024, 0x0006, 0xd312, 0x0006, 0xd310, 0x0006, + 0x8191, 0x3010, 0x984c, 0x30f0, 0xc024, 0x0000, 0x0021, 0xf2d6, 0x07c6, + 0x290a, 0xf5c0, 0x4682, 0x0400, 0x6894, 0x0840, 0xb886, 0x0bc1, 0xbcd6, + 0x0024, 0x3a10, 0x8024, 0x3af0, 0xc024, 0x36f3, 0x4024, 0x36f3, 0xd80e, + 0x36f4, 0x9813, 0x36f4, 0x1811, 0x36f1, 0x9807, 0x36f1, 0x1805, 0x36f0, + 0x9803, 0x36f0, 0x1801, 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, + 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, + 0x3815, 0x3e05, 0xb814, 0x3615, 0x0024, 0x0000, 0x800a, 0x3e10, 0x3801, + 0x0020, 0x0001, 0x3e14, 0x3811, 0x0030, 0x0050, 0x0030, 0x0251, 0x3e04, + 0xb813, 0x3000, 0x0024, 0xc012, 0x0024, 0x0019, 0x9300, 0x3800, 0x4024, + 0x2903, 0x8c40, 0x3900, 0x0024, 0x2903, 0xa040, 0x0000, 0x0300, 0xb882, + 0x0024, 0x2914, 0xbec0, 0x0006, 0x8010, 0x0000, 0x1540, 0x0007, 0x8190, + 0x2901, 0x8200, 0x3800, 0x0024, 0x4080, 0x0024, 0x0000, 0x0024, 0x2803, + 0x2f55, 0x0000, 0x0024, 0x0006, 0x8012, 0x3200, 0x0024, 0x4080, 0x0024, + 0x0030, 0x0010, 0x2803, 0x2f55, 0x0000, 0x0201, 0x3000, 0x0024, 0xb010, + 0x0024, 0x0000, 0x0024, 0x2803, 0x2f55, 0x0000, 0x0024, 0x2901, 0x8200, + 0x0000, 0x0024, 0x4080, 0x0024, 0x0006, 0x8010, 0x2803, 0x2f55, 0x3000, + 0x0024, 0x4080, 0x0024, 0x0000, 0x0201, 0x2803, 0x2b85, 0x0030, 0x0010, + 0x0030, 0x0050, 0xf292, 0x0000, 0xb012, 0x0024, 0x3800, 0x4024, 0x0030, + 0x0010, 0x0000, 0x0201, 0x3000, 0x0024, 0xb010, 0x0024, 0x0000, 0x0024, + 0x2900, 0xbed5, 0x0003, 0x3908, 0x0006, 0x8011, 0x3100, 0x0024, 0x4080, + 0x0024, 0x0000, 0x0024, 0x2803, 0x3745, 0x0000, 0x0024, 0x0007, 0x8a52, + 0x3200, 0x0024, 0x4080, 0x0024, 0x0000, 0x0024, 0x2803, 0x3749, 0x0000, + 0x0024, 0xf292, 0x0800, 0x6012, 0x0024, 0x0000, 0x0000, 0x2803, 0x3705, + 0x0000, 0x0024, 0x3200, 0x0024, 0x4090, 0x0024, 0xb880, 0x2800, 0x3900, + 0x0024, 0x3100, 0x0024, 0x4080, 0x0024, 0x0000, 0x0024, 0x2902, 0x3585, + 0x0003, 0x3048, 0x2900, 0xbec0, 0x0000, 0x0024, 0x0000, 0x0010, 0x0006, + 0x9f51, 0x0006, 0x9f92, 0x0030, 0x0493, 0x0000, 0x0201, 0x6890, 0xa410, + 0x3b00, 0x2810, 0x0006, 0x8a10, 0x3009, 0x0000, 0x6012, 0x0024, 0x0006, + 0x9fd0, 0x2803, 0x3c88, 0xb880, 0x0024, 0x6890, 0x0024, 0x3009, 0x2000, + 0x36f4, 0x9813, 0x36f4, 0x1811, 0x36f0, 0x1801, 0x3405, 0x9014, 0x36f3, + 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, 0x0024, + 0x3e10, 0xb810, 0x3e11, 0x3805, 0x3e02, 0x0024, 0x0030, 0x0010, 0xce9a, + 0x0002, 0x0000, 0x0200, 0x2903, 0x47c0, 0xb024, 0x0024, 0xc020, 0x0024, + 0x0000, 0x0200, 0x2803, 0x4085, 0x6e9a, 0x0002, 0x4182, 0x0024, 0x0000, + 0x0400, 0x2803, 0x4645, 0xae1a, 0x0024, 0x6104, 0x984c, 0x0000, 0x0024, + 0x2900, 0xb749, 0x0003, 0x4608, 0x6103, 0xe4e5, 0x2900, 0xb740, 0x408a, + 0x188c, 0x2900, 0xb740, 0x408a, 0x4141, 0x4583, 0x6465, 0x2803, 0x4640, + 0xceca, 0x1bcc, 0xc408, 0x0024, 0xf2e2, 0x1bc8, 0x36f1, 0x1805, 0x2000, + 0x0011, 0x36f0, 0x9810, 0x2000, 0x0000, 0xdc92, 0x0024, 0x0006, 0x8a17, + 0x3613, 0x1c00, 0x6093, 0xe1e3, 0x0000, 0x03c3, 0x0006, 0x9f95, 0xb132, + 0x9415, 0x3500, 0xfc01, 0x2803, 0x55d5, 0xa306, 0x0024, 0x0006, 0xd397, + 0x003f, 0xc001, 0x3500, 0x184c, 0xb011, 0xe4e5, 0xb182, 0x1c04, 0xd400, + 0x184c, 0x0000, 0x0205, 0xac52, 0x3802, 0x0006, 0xd3c2, 0x4212, 0x0024, + 0xf400, 0x4057, 0xb182, 0x1c04, 0xd400, 0x0024, 0xac52, 0x1404, 0xd142, + 0x0024, 0x0000, 0x3fc4, 0xb142, 0x0024, 0x4122, 0x1bc2, 0xf400, 0x4057, + 0x3700, 0x4024, 0xd101, 0x6465, 0x0006, 0xd397, 0x3f00, 0x3814, 0x0025, + 0xffd4, 0x0006, 0xd317, 0x3710, 0x160c, 0x0006, 0x9f94, 0x37f0, 0x73d5, + 0x6c92, 0x3808, 0x3f10, 0x0024, 0x3ff0, 0x4024, 0x3009, 0x1040, 0x3009, + 0x13c1, 0x6010, 0x0024, 0x0000, 0x0024, 0x2903, 0xa905, 0x0003, 0x51c8, + 0x2803, 0x5414, 0x0006, 0x0001, 0x4010, 0x0024, 0x0005, 0xf601, 0x6010, + 0x0024, 0x0000, 0x0040, 0x2803, 0x5594, 0x0030, 0x0497, 0x3f00, 0x0024, + 0x36f2, 0x1814, 0x4330, 0x9803, 0x2000, 0x0000, 0x8880, 0x1bc1, 0x3613, + 0x0024, 0x3e22, 0xb806, 0x3e05, 0xb814, 0x3615, 0x0024, 0x0000, 0x800a, + 0x3e10, 0x3801, 0x3e10, 0xb803, 0x3e11, 0x7807, 0x6848, 0x930c, 0x3411, + 0x780d, 0x459a, 0x10c0, 0x0000, 0x0201, 0x6012, 0x384e, 0x0000, 0x0241, + 0x2803, 0x5d15, 0x6012, 0x380f, 0x2403, 0x5c45, 0x0000, 0x0024, 0x3000, + 0x0001, 0x3101, 0x8407, 0x6cfe, 0x0024, 0xac42, 0x0024, 0xaf4e, 0x2040, + 0x3911, 0x8024, 0x2803, 0x68c0, 0x0000, 0x0024, 0x0000, 0x0281, 0x2803, + 0x6055, 0x6012, 0x4455, 0x2403, 0x5f85, 0x0000, 0x0024, 0x3000, 0x0001, + 0x3101, 0x8407, 0x4cf2, 0x0024, 0xac42, 0x0024, 0xaf4e, 0x2040, 0x3911, + 0x8024, 0x2803, 0x68c0, 0x0000, 0x0024, 0x0000, 0x0024, 0x2803, 0x6495, + 0x4080, 0x0024, 0x3110, 0x0401, 0xf20f, 0x0203, 0x2403, 0x63c5, 0x8dd6, + 0x0024, 0x4dce, 0x0024, 0xf1fe, 0x0024, 0xaf4e, 0x0024, 0x6dc6, 0x2046, + 0xf1df, 0x0203, 0xaf4f, 0x1011, 0xf20e, 0x07cc, 0x8dd6, 0x2486, 0x2803, + 0x68c0, 0x0000, 0x0024, 0x0000, 0x0024, 0x2803, 0x6715, 0x0000, 0x0024, + 0x0fff, 0xffd1, 0x2403, 0x6645, 0x3010, 0x0001, 0xac4f, 0x0801, 0x3821, + 0x8024, 0x2803, 0x68c0, 0x0000, 0x0024, 0x0fff, 0xffd1, 0x2403, 0x6885, + 0x3010, 0x0001, 0x3501, 0x9407, 0xac47, 0x0801, 0xaf4e, 0x2082, 0x3d11, + 0x8024, 0x36f3, 0xc024, 0x36f3, 0x980d, 0x36f1, 0x5807, 0x36f0, 0x9803, + 0x36f0, 0x1801, 0x3405, 0x9014, 0x36e3, 0x0024, 0x2000, 0x0000, 0x36f2, + 0x9806, 0x0006, 0x9f97, 0x3e00, 0x5c15, 0x0006, 0xd397, 0x003f, 0xc001, + 0x3500, 0x3840, 0xb011, 0xe4e5, 0xb182, 0x1c04, 0xd400, 0x184c, 0x0000, + 0x0205, 0xac52, 0x3802, 0x0006, 0xd3c2, 0x4212, 0x0024, 0xb182, 0x4057, + 0x3701, 0x0024, 0xd400, 0x0024, 0xac52, 0x1404, 0xd142, 0x0024, 0x0000, + 0x3fc4, 0xb142, 0x0024, 0x4122, 0x1bc2, 0xf400, 0x4057, 0x3700, 0x4024, + 0xd101, 0x6465, 0x0006, 0xd397, 0x3f00, 0x3814, 0x0025, 0xffd4, 0x0006, + 0xd317, 0x3710, 0x160c, 0x0006, 0x9f94, 0x37f0, 0x73d5, 0x6c92, 0x0024, + 0x3f10, 0x1040, 0x3ff0, 0x53c1, 0x6010, 0x0024, 0x0000, 0x0024, 0x2803, + 0x7494, 0x0006, 0x0001, 0x4010, 0x0024, 0x0005, 0xf601, 0x6010, 0x9bd4, + 0x0000, 0x0040, 0x2803, 0x7614, 0x0030, 0x0497, 0x3f00, 0x0024, 0x2000, + 0x0000, 0x36f0, 0x5800, 0x0000, 0x0400, 0x6102, 0x0024, 0x3e11, 0x3805, + 0x2803, 0x7989, 0x3e02, 0x0024, 0x2900, 0xb740, 0x408a, 0x188c, 0x2900, + 0xb740, 0x408a, 0x4141, 0x4582, 0x1bc8, 0x2000, 0x0000, 0x36f1, 0x1805, + 0x2900, 0xb740, 0x4102, 0x184c, 0xb182, 0x1bc8, 0x2000, 0x0000, 0x36f1, + 0x1805, 0x3613, 0x0024, 0x3e12, 0xb815, 0x3e11, 0xb807, 0x3e13, 0xf80e, + 0x3e03, 0x4024, 0x680c, 0x0024, 0x0000, 0x0024, 0x2803, 0x7ed8, 0x409c, + 0x0024, 0x2403, 0x7e86, 0x0000, 0x000a, 0x3111, 0xc024, 0xfe4e, 0x0007, + 0x47be, 0x0024, 0xf6fe, 0x0024, 0x3811, 0xc024, 0x36f3, 0x4024, 0x36f3, + 0xd80e, 0x36f1, 0x9807, 0x2000, 0x0000, 0x36f2, 0x9815, 0x3613, 0x0024, + 0x3e12, 0xb815, 0x3e11, 0xb807, 0x3e13, 0xf80e, 0x3e03, 0x4024, 0x680c, + 0x0024, 0x0000, 0x0024, 0x2803, 0x8418, 0x409c, 0x0024, 0x2403, 0x83c6, + 0x0000, 0x000a, 0x3111, 0xc024, 0xfe4e, 0x8007, 0x47be, 0x0024, 0xf6fe, + 0x0024, 0x3009, 0x2047, 0x36f3, 0x4024, 0x36f3, 0xd80e, 0x36f1, 0x9807, + 0x2000, 0x0000, 0x36f2, 0x9815, 0x2a03, 0x858e, 0x3e12, 0xb817, 0x3e10, + 0x3802, 0x0000, 0x800a, 0x0006, 0x9f97, 0x3009, 0x1fc2, 0x3e04, 0x5c00, + 0x6020, 0xb810, 0x0030, 0x0451, 0x2803, 0x8854, 0x0006, 0x0002, 0x4020, + 0x0024, 0x0005, 0xfb02, 0x6024, 0x0024, 0x0025, 0xffd0, 0x2803, 0x8a91, + 0x3100, 0x1c11, 0xb284, 0x0024, 0x0030, 0x0490, 0x3800, 0x8024, 0x0025, + 0xffd0, 0x3980, 0x1810, 0x36f4, 0x7c11, 0x36f0, 0x1802, 0x0030, 0x0717, + 0x3602, 0x8024, 0x2100, 0x0000, 0x3f05, 0xdbd7, 0x0003, 0x8557, 0x3613, + 0x0024, 0x3e00, 0x3801, 0xf400, 0x55c0, 0x0000, 0x0897, 0xf400, 0x57c0, + 0x0000, 0x0024, 0x2000, 0x0000, 0x36f0, 0x1801, 0x0006, 0xd397, 0x2000, + 0x0000, 0x3700, 0x0024, 0xb183, 0xe1e3, 0x0000, 0x0203, 0xac32, 0x40d5, + 0xd122, 0x0024, 0x0000, 0x3fc3, 0xb132, 0x0024, 0x0006, 0xd3c3, 0x4316, + 0x0024, 0xf400, 0x40d5, 0x3500, 0x5803, 0x2000, 0x0000, 0xd010, 0x1bc1, + 0x3613, 0x0024, 0x3e22, 0xb815, 0x3e05, 0xb814, 0x3615, 0x0024, 0x0000, + 0x800a, 0x3e10, 0x3801, 0x3e10, 0xb803, 0xb884, 0xb805, 0xb888, 0x3844, + 0x3e11, 0xb80d, 0x3e03, 0xf80e, 0x0000, 0x03ce, 0xf400, 0x4083, 0x2403, + 0x9ace, 0xf400, 0x4105, 0x0000, 0x0206, 0xa562, 0x0024, 0x455a, 0x0024, + 0x0020, 0x0006, 0xd312, 0x0024, 0xb16c, 0x0024, 0x0020, 0x0006, 0x2803, + 0x9945, 0xd342, 0x0024, 0x0000, 0x01c6, 0xd342, 0x0024, 0xd56a, 0x0024, + 0x0020, 0x0006, 0x4448, 0x0024, 0xb16c, 0x0024, 0x0020, 0x0146, 0x2803, + 0x9ac5, 0x0000, 0x0024, 0xd468, 0x0024, 0x4336, 0x0024, 0x0000, 0x4000, + 0x0006, 0xd3c1, 0x0006, 0x9306, 0x4122, 0x0024, 0x462c, 0x4055, 0x4092, + 0x3404, 0xb512, 0x4195, 0x6294, 0x3401, 0x6200, 0x0024, 0x0000, 0x03ce, + 0x2803, 0x9551, 0xb888, 0x0024, 0x36f3, 0xd80e, 0x36f1, 0x980d, 0x36f1, + 0x1805, 0x36f0, 0x9803, 0x36f0, 0x1801, 0x3405, 0x9014, 0x36e3, 0x0024, + 0x2000, 0x0000, 0x36f2, 0x9815, 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, + 0x3815, 0x3e05, 0xb814, 0x3615, 0x0024, 0x0000, 0x800a, 0x3e10, 0x3801, + 0xb880, 0xb810, 0x0006, 0x9fd0, 0x3e10, 0x8001, 0x4182, 0x3811, 0x0006, + 0xd311, 0x2803, 0xa405, 0x0006, 0x8a10, 0x0000, 0x0200, 0xbc82, 0xa000, + 0x3910, 0x0024, 0x2903, 0x9240, 0x39f0, 0x4024, 0x0006, 0x9f90, 0x0006, + 0x9f51, 0x3009, 0x0000, 0x3009, 0x0401, 0x6014, 0x0024, 0x0000, 0x0024, + 0x2903, 0xa905, 0x0003, 0xa508, 0x36f4, 0x4024, 0x36f0, 0x9810, 0x36f0, + 0x1801, 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, + 0x36f2, 0x9817, 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, + 0xb814, 0x290a, 0xd900, 0x3605, 0x0024, 0x2910, 0x0180, 0x3613, 0x0024, + 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, + 0x9817, 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, + 0x3615, 0x0024, 0x0000, 0x800a, 0x3e10, 0xb803, 0x0006, 0x0002, 0x3e11, + 0x3805, 0x3e11, 0xb807, 0x3e14, 0x3811, 0x0006, 0x9f90, 0x3e04, 0xb813, + 0x3009, 0x0012, 0x3213, 0x0024, 0xf400, 0x4480, 0x6026, 0x0024, 0x0000, + 0x0024, 0x2803, 0xb195, 0x0000, 0x0024, 0x0000, 0x0012, 0xf400, 0x4480, + 0x0006, 0x9f50, 0x3009, 0x0002, 0x6026, 0x0024, 0x0000, 0x0024, 0x2903, + 0xa905, 0x0003, 0xb188, 0x0006, 0x9f93, 0x3201, 0x0c11, 0xb58a, 0x0406, + 0x0006, 0x8a11, 0x468e, 0x8400, 0xb68c, 0x9813, 0xcfee, 0x1bd2, 0x0000, + 0x0804, 0xaf0e, 0x9811, 0x4f86, 0x1bd0, 0x0000, 0x0021, 0x6418, 0x9807, + 0x6848, 0x1bc6, 0xad46, 0x9805, 0xf400, 0x4080, 0x36f1, 0x0024, 0x36f0, + 0x9803, 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, + 0x36f2, 0x9817, 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, + 0xb814, 0x3615, 0x0024, 0x0000, 0x800a, 0x3e10, 0x3801, 0x3e10, 0xb803, + 0x3e11, 0x3805, 0x2803, 0xbfc0, 0x3e04, 0x3811, 0x0000, 0x0401, 0x2900, + 0xb740, 0x3613, 0x0024, 0x0000, 0x0080, 0xb882, 0x130c, 0xf400, 0x4510, + 0x3010, 0x910c, 0x30f0, 0xc024, 0x6dc2, 0x0024, 0x3810, 0x0024, 0x38f0, + 0x4024, 0x0000, 0x0201, 0x3100, 0x0024, 0xb010, 0x0024, 0x0000, 0x0024, + 0x2803, 0xc315, 0x0000, 0x0024, 0x6894, 0x130c, 0xb886, 0x1040, 0x3430, + 0x4024, 0x6dca, 0x0024, 0x0030, 0x0011, 0x2803, 0xbb91, 0x0000, 0x0024, + 0xbcd2, 0x0024, 0x0000, 0x0201, 0x2803, 0xc305, 0x0000, 0x0024, 0x2900, + 0xb740, 0x3613, 0x0024, 0x36f4, 0x1811, 0x36f1, 0x1805, 0x36f0, 0x9803, + 0x36f0, 0x1801, 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, + 0x0000, 0x36f2, 0x9817, 0x3613, 0x0024, 0x3e12, 0xb815, 0x0000, 0x800a, + 0x3e14, 0x7813, 0x3e10, 0xb803, 0x3e11, 0x3805, 0x3e11, 0xb807, 0x3e13, + 0xf80e, 0x6812, 0x0024, 0x3e03, 0x7810, 0x0fff, 0xffd3, 0x0000, 0x0091, + 0xbd86, 0x9850, 0x3e10, 0x3804, 0x3e00, 0x7812, 0xbe8a, 0x8bcc, 0x409e, + 0x8086, 0x2403, 0xca47, 0xfe49, 0x2821, 0x526a, 0x8801, 0x5c87, 0x280e, + 0x4eba, 0x9812, 0x4286, 0x40e1, 0xb284, 0x1bc1, 0x4de6, 0x0024, 0xad17, + 0x2627, 0x4fde, 0x9804, 0x4498, 0x1bc0, 0x0000, 0x0024, 0x2803, 0xc855, + 0x3a11, 0xa807, 0x36f3, 0x4024, 0x36f3, 0xd80e, 0x36f1, 0x9807, 0x36f1, + 0x1805, 0x36f0, 0x9803, 0x36f4, 0x5813, 0x2000, 0x0000, 0x36f2, 0x9815, + 0x3613, 0x0024, 0x3e12, 0xb815, 0x0000, 0x800a, 0x3e10, 0xb803, 0x3e11, + 0x3805, 0x3e11, 0xb807, 0x3e13, 0xf80e, 0x6812, 0x0024, 0x3e03, 0x7810, + 0x3009, 0x1850, 0x3e10, 0x3804, 0x3e10, 0x7812, 0x32f3, 0x0024, 0xbd86, + 0x0024, 0x4091, 0xe2e3, 0x3009, 0x0046, 0x2403, 0xd5c0, 0x3009, 0x0047, + 0x32f0, 0x0801, 0xfe1f, 0x6465, 0x5e8a, 0x0024, 0x44ba, 0x0024, 0xfee2, + 0x0024, 0x5d8a, 0x1800, 0x4482, 0x4160, 0x48ba, 0x8046, 0x4dc6, 0x1822, + 0x4de6, 0x8047, 0x36f3, 0x0024, 0x36f0, 0x5812, 0xad17, 0x2627, 0x4fde, + 0x9804, 0x4498, 0x1bc0, 0x0000, 0x0024, 0x2803, 0xd155, 0x3a11, 0xa807, + 0x36f3, 0x4024, 0x36f3, 0xd80e, 0x36f1, 0x9807, 0x36f1, 0x1805, 0x36f0, + 0x9803, 0x2000, 0x0000, 0x36f2, 0x9815, 0xb386, 0x40d7, 0x4284, 0x184c, + 0x0000, 0x05c0, 0x2803, 0xdb55, 0xf5d8, 0x3804, 0x0000, 0x0984, 0x6400, + 0xb84a, 0x3e13, 0xf80d, 0xa204, 0x380e, 0x0000, 0x800a, 0x0000, 0x00ce, + 0x2403, 0xde8e, 0xffa4, 0x0024, 0x48b6, 0x0024, 0x0000, 0x0024, 0x2803, + 0xde84, 0x4000, 0x40c2, 0x4224, 0x0024, 0x6090, 0x0024, 0xffa4, 0x0024, + 0x0fff, 0xfe83, 0xfe86, 0x1bce, 0x36f3, 0xd80d, 0x48b6, 0x0024, 0x0fff, + 0xff03, 0xa230, 0x45c3, 0x2000, 0x0000, 0x36f1, 0x180a, 0x4080, 0x184c, + 0x3e13, 0x780f, 0x2803, 0xe2c5, 0x4090, 0xb80e, 0x2403, 0xe240, 0x3e04, + 0x0440, 0x3810, 0x0440, 0x3604, 0x0024, 0x3009, 0x1bce, 0x3603, 0x5bcf, + 0x2000, 0x0000, 0x0000, 0x0024, 0x0007, 0x0001, /*copy 1*/ + 0x802e, 0x0006, 0x0002, /*copy 2*/ + 0x2801, 0x6ac0, 0x0007, 0x0001, /*copy 1*/ + 0x8030, 0x0006, 0x0002, /*copy 2*/ + 0x2800, 0x1b40, 0x0007, 0x0001, /*copy 1*/ + 0x8028, 0x0006, 0x0002, /*copy 2*/ + 0x2a00, 0x144e, 0x0007, 0x0001, /*copy 1*/ + 0x8032, 0x0006, 0x0002, /*copy 2*/ + 0x2800, 0x7140, 0x0007, 0x0001, /*copy 1*/ + 0x3580, 0x0006, 0x8038, 0x0000, /*Rle(56)*/ + 0x0007, 0x0001, /*copy 1*/ + 0xfab3, 0x0006, 0x01a4, /*copy 420*/ + 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, 0xffff, 0xfffe, 0xfffb, 0xfff9, + 0xfff5, 0xfff2, 0xffed, 0xffe8, 0xffe3, 0xffde, 0xffd8, 0xffd3, 0xffce, + 0xffca, 0xffc7, 0xffc4, 0xffc4, 0xffc5, 0xffc7, 0xffcc, 0xffd3, 0xffdc, + 0xffe6, 0xfff3, 0x0001, 0x0010, 0x001f, 0x002f, 0x003f, 0x004e, 0x005b, + 0x0066, 0x006f, 0x0074, 0x0075, 0x0072, 0x006b, 0x005f, 0x004f, 0x003c, + 0x0024, 0x0009, 0xffed, 0xffcf, 0xffb0, 0xff93, 0xff77, 0xff5f, 0xff4c, + 0xff3d, 0xff35, 0xff34, 0xff3b, 0xff4a, 0xff60, 0xff7e, 0xffa2, 0xffcd, + 0xfffc, 0x002e, 0x0061, 0x0094, 0x00c4, 0x00f0, 0x0114, 0x0131, 0x0144, + 0x014b, 0x0146, 0x0134, 0x0116, 0x00eb, 0x00b5, 0x0075, 0x002c, 0xffde, + 0xff8e, 0xff3d, 0xfeef, 0xfea8, 0xfe6a, 0xfe39, 0xfe16, 0xfe05, 0xfe06, + 0xfe1b, 0xfe43, 0xfe7f, 0xfecd, 0xff2a, 0xff95, 0x0009, 0x0082, 0x00fd, + 0x0173, 0x01e1, 0x0242, 0x0292, 0x02cc, 0x02ec, 0x02f2, 0x02da, 0x02a5, + 0x0253, 0x01e7, 0x0162, 0x00c9, 0x0021, 0xff70, 0xfebc, 0xfe0c, 0xfd68, + 0xfcd5, 0xfc5b, 0xfc00, 0xfbc9, 0xfbb8, 0xfbd2, 0xfc16, 0xfc85, 0xfd1b, + 0xfdd6, 0xfeae, 0xff9e, 0x009c, 0x01a0, 0x02a1, 0x0392, 0x046c, 0x0523, + 0x05b0, 0x060a, 0x062c, 0x0613, 0x05bb, 0x0526, 0x0456, 0x0351, 0x021f, + 0x00c9, 0xff5a, 0xfde1, 0xfc6a, 0xfb05, 0xf9c0, 0xf8aa, 0xf7d0, 0xf73d, + 0xf6fa, 0xf70f, 0xf77e, 0xf848, 0xf96b, 0xfadf, 0xfc9a, 0xfe8f, 0x00ad, + 0x02e3, 0x051a, 0x073f, 0x0939, 0x0af4, 0x0c5a, 0x0d59, 0x0de1, 0x0de5, + 0x0d5c, 0x0c44, 0x0a9e, 0x0870, 0x05c7, 0x02b4, 0xff4e, 0xfbaf, 0xf7f8, + 0xf449, 0xf0c7, 0xed98, 0xeae0, 0xe8c4, 0xe765, 0xe6e3, 0xe756, 0xe8d2, + 0xeb67, 0xef19, 0xf3e9, 0xf9cd, 0x00b5, 0x088a, 0x112b, 0x1a72, 0x2435, + 0x2e42, 0x3866, 0x426b, 0x4c1b, 0x553e, 0x5da2, 0x6516, 0x6b6f, 0x7087, + 0x7441, 0x7686, 0x774a, 0x7686, 0x7441, 0x7087, 0x6b6f, 0x6516, 0x5da2, + 0x553e, 0x4c1b, 0x426b, 0x3866, 0x2e42, 0x2435, 0x1a72, 0x112b, 0x088a, + 0x00b5, 0xf9cd, 0xf3e9, 0xef19, 0xeb67, 0xe8d2, 0xe756, 0xe6e3, 0xe765, + 0xe8c4, 0xeae0, 0xed98, 0xf0c7, 0xf449, 0xf7f8, 0xfbaf, 0xff4e, 0x02b4, + 0x05c7, 0x0870, 0x0a9e, 0x0c44, 0x0d5c, 0x0de5, 0x0de1, 0x0d59, 0x0c5a, + 0x0af4, 0x0939, 0x073f, 0x051a, 0x02e3, 0x00ad, 0xfe8f, 0xfc9a, 0xfadf, + 0xf96b, 0xf848, 0xf77e, 0xf70f, 0xf6fa, 0xf73d, 0xf7d0, 0xf8aa, 0xf9c0, + 0xfb05, 0xfc6a, 0xfde1, 0xff5a, 0x00c9, 0x021f, 0x0351, 0x0456, 0x0526, + 0x05bb, 0x0613, 0x062c, 0x060a, 0x05b0, 0x0523, 0x046c, 0x0392, 0x02a1, + 0x01a0, 0x009c, 0xff9e, 0xfeae, 0xfdd6, 0xfd1b, 0xfc85, 0xfc16, 0xfbd2, + 0xfbb8, 0xfbc9, 0xfc00, 0xfc5b, 0xfcd5, 0xfd68, 0xfe0c, 0xfebc, 0xff70, + 0x0021, 0x00c9, 0x0162, 0x01e7, 0x0253, 0x02a5, 0x02da, 0x02f2, 0x02ec, + 0x02cc, 0x0292, 0x0242, 0x01e1, 0x0173, 0x00fd, 0x0082, 0x0009, 0xff95, + 0xff2a, 0xfecd, 0xfe7f, 0xfe43, 0xfe1b, 0xfe06, 0xfe05, 0xfe16, 0xfe39, + 0xfe6a, 0xfea8, 0xfeef, 0xff3d, 0xff8e, 0xffde, 0x002c, 0x0075, 0x00b5, + 0x00eb, 0x0116, 0x0134, 0x0146, 0x014b, 0x0144, 0x0131, 0x0114, 0x00f0, + 0x00c4, 0x0094, 0x0061, 0x002e, 0xfffc, 0xffcd, 0xffa2, 0xff7e, 0xff60, + 0xff4a, 0xff3b, 0xff34, 0xff35, 0xff3d, 0xff4c, 0xff5f, 0xff77, 0xff93, + 0xffb0, 0xffcf, 0xffed, 0x0009, 0x0024, 0x003c, 0x004f, 0x005f, 0x006b, + 0x0072, 0x0075, 0x0074, 0x006f, 0x0066, 0x005b, 0x004e, 0x003f, 0x002f, + 0x001f, 0x0010, 0x0001, 0xfff3, 0xffe6, 0xffdc, 0xffd3, 0xffcc, 0xffc7, + 0xffc5, 0xffc4, 0xffc4, 0xffc7, 0xffca, 0xffce, 0xffd3, 0xffd8, 0xffde, + 0xffe3, 0xffe8, 0xffed, 0xfff2, 0xfff5, 0xfff9, 0xfffb, 0xfffe, 0xffff, + 0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, 0x0007, 0x0001, /*copy 1*/ + 0x180b, 0x0006, 0x000d, /*copy 13*/ + 0x000f, 0x0010, 0x001c, 0xfab3, 0x3580, 0x8037, 0xa037, 0x0001, 0x0000, + 0x3580, 0x01a4, 0x0728, 0x0746, 0x0006, 0x8006, 0x078e, /*Rle(6)*/ + 0x0006, 0x0027, /*copy 39*/ + 0x0763, 0x0763, 0x0763, 0x0763, 0x0763, 0x0992, 0x0976, 0x097a, 0x097e, + 0x0982, 0x0986, 0x098a, 0x098e, 0x09c1, 0x09c5, 0x09c8, 0x09c8, 0x09c8, + 0x09c8, 0x09d0, 0x09e3, 0x0aae, 0x0a1a, 0x0a1f, 0x0a25, 0x0a2b, 0x0a30, + 0x0a35, 0x0a3a, 0x0a3f, 0x0a44, 0x0a49, 0x0a4e, 0x0a53, 0x0a6c, 0x0a8b, + 0x0aaa, 0x5a82, 0x5a82, 0x0006, 0x8006, 0x0000, /*Rle(6)*/ + 0x0006, 0x0018, /*copy 24*/ + 0x6fb8, 0xc180, 0xc180, 0x6fb8, 0x0000, 0x0000, 0x0000, 0x0000, 0x5a82, + 0x5a82, 0x6fb8, 0xc180, 0xc180, 0x6fb8, 0x0000, 0x0000, 0x5a82, 0x5a82, + 0x5a82, 0x5a82, 0x6fb8, 0xc180, 0xc180, 0x6fb8, 0x0007, 0x0001, /*copy 1*/ + 0x8025, 0x0006, 0x0002, /*copy 2*/ + 0x2a00, 0x5c4e, 0x0007, 0x0001, /*copy 1*/ + 0x5800, 0x0006, 0x0001, /*copy 1*/ + 0x0001, 0x0006, 0x8007, 0x0000, /*Rle(7)*/ + 0x0006, 0x0018, /*copy 24*/ + 0x0002, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0003, + 0x0000, 0xfffd, 0xffff, 0x0001, 0x0000, 0x0000, 0x0000, 0x0004, 0x0000, + 0xfffa, 0xffff, 0x0004, 0x0000, 0xffff, 0xffff, 0x000a, 0x0001, /*copy 1*/ + 0x0050, +#define PLUGIN_SIZE 8414 +#ifndef SKIP_PLUGIN_VARNAME +}; +#endif diff --git a/targets/esp32/components/VS1053/include/patches_flac_latm.h b/targets/esp32/components/VS1053/include/patches_flac_latm.h new file mode 100644 index 00000000..e44ba0ba --- /dev/null +++ b/targets/esp32/components/VS1053/include/patches_flac_latm.h @@ -0,0 +1,980 @@ + +#ifndef SKIP_PLUGIN_VARNAME +const unsigned short PLUGIN[] = { + /* Compressed plugin */ +#endif + 0x0007, 0x0001, /*copy 1*/ + 0x8050, 0x0006, 0x0558, /*copy 1368*/ + 0x2a00, 0xc000, 0x3e12, 0x3800, 0x3e00, 0xb804, 0x0030, 0x0015, 0x0007, + 0x8257, 0x3700, 0x984c, 0xf224, 0x1444, 0xf224, 0x0024, 0x0008, 0x0002, + 0x2910, 0x0181, 0x0000, 0x14c8, 0xb428, 0x1402, 0x0000, 0x8004, 0x2910, + 0x0195, 0x0000, 0x14c8, 0xb428, 0x0024, 0x0006, 0x0095, 0x2800, 0x2245, + 0x3e13, 0x780e, 0x3e11, 0x7803, 0x3e13, 0xf806, 0x3e11, 0xf801, 0x3510, + 0xb808, 0x003f, 0xe004, 0xfec4, 0x3800, 0x48be, 0x17c3, 0xfec6, 0x41c2, + 0x48be, 0x4497, 0x4090, 0x1c46, 0xf06c, 0x0024, 0x2400, 0x1e80, 0x6090, + 0x41c3, 0x6628, 0x1c47, 0x0000, 0x0024, 0x2800, 0x1d49, 0xf07e, 0x0024, + 0xf400, 0x4182, 0x673a, 0x1c46, 0x0000, 0x0024, 0x2800, 0x1e89, 0xf06c, + 0x0024, 0xf400, 0x41c3, 0x0000, 0x0024, 0x4224, 0x3442, 0x2903, 0xf500, + 0x4336, 0x37c3, 0x0000, 0x1805, 0x2903, 0xf500, 0x4508, 0x40c2, 0x450a, + 0x9808, 0x0000, 0x0207, 0xa478, 0x1bc0, 0xc45a, 0x1807, 0x0030, 0x03d5, + 0x3d01, 0x5bc1, 0x36f3, 0xd806, 0x3601, 0x5803, 0x36f3, 0x0024, 0x36f3, + 0x580e, 0x0007, 0x8257, 0x0000, 0x6004, 0x3730, 0x8024, 0xb244, 0x1c04, + 0xd428, 0x3c02, 0x0006, 0xc717, 0x2800, 0x2605, 0x4284, 0x0024, 0x3613, + 0x3c02, 0x0006, 0xc357, 0x2901, 0x6280, 0x3e11, 0x5c05, 0x4284, 0x1bc5, + 0x0000, 0x0024, 0x2800, 0x2945, 0x0000, 0x0024, 0x0030, 0x0117, 0x3f00, + 0x0024, 0x3613, 0x0024, 0x3e10, 0x3813, 0x3e14, 0x8024, 0x3e04, 0x8024, + 0x2900, 0x48c0, 0x0006, 0x02d3, 0x36e3, 0x0024, 0x3009, 0x1bd3, 0x0007, + 0x8257, 0x3700, 0x8024, 0xf224, 0x0024, 0x0000, 0x0024, 0x2800, 0x2b51, + 0x3600, 0x9844, 0x2900, 0x3100, 0x0000, 0x2bc8, 0x2911, 0xf140, 0x0000, + 0x0024, 0x0030, 0x0057, 0x3700, 0x0024, 0xf200, 0x4595, 0x0fff, 0xfe02, + 0xa024, 0x164c, 0x8000, 0x17cc, 0x3f00, 0x0024, 0x3500, 0x0024, 0x0021, + 0x6d82, 0xd024, 0x44c0, 0x0006, 0xa402, 0x2800, 0x3015, 0xd024, 0x0024, + 0x0000, 0x0000, 0x2800, 0x3015, 0x000b, 0x6d57, 0x3009, 0x3c00, 0x36f0, + 0x8024, 0x36f2, 0x1800, 0x2000, 0x0000, 0x0000, 0x0024, 0x3e14, 0x7810, + 0x3e13, 0xb80d, 0x3e13, 0xf80a, 0x3e10, 0xb803, 0x3e11, 0x3805, 0x3e11, + 0xb807, 0x3e14, 0xf801, 0x3e15, 0x3815, 0x0001, 0x000a, 0x0006, 0xc4d7, + 0xbf8e, 0x9c42, 0x3e01, 0x9c03, 0x0006, 0xa017, 0x0023, 0xffd1, 0x0007, + 0x8250, 0x0fff, 0xfd85, 0x3001, 0x0024, 0xa45a, 0x4494, 0x0000, 0x0093, + 0x2800, 0x3751, 0xf25a, 0x104c, 0x34f3, 0x0024, 0x2800, 0x3751, 0x0000, + 0x0024, 0x3413, 0x084c, 0x0000, 0x0095, 0x3281, 0xf806, 0x4091, 0x4d64, + 0x2400, 0x3980, 0x4efa, 0x9c10, 0xf1eb, 0x6061, 0xfe55, 0x2f66, 0x5653, + 0x4d64, 0x48b2, 0xa201, 0x4efa, 0xa201, 0x36f3, 0x3c10, 0x36f5, 0x1815, + 0x36f4, 0xd801, 0x36f1, 0x9807, 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f3, + 0xd80a, 0x36f3, 0x980d, 0x2000, 0x0000, 0x36f4, 0x5810, 0x3e12, 0xb817, + 0x3e14, 0xf812, 0x3e01, 0xb811, 0x0007, 0x9717, 0x0020, 0xffd2, 0x0030, + 0x11d1, 0x3111, 0x8024, 0x3704, 0xc024, 0x3b81, 0x8024, 0x3101, 0x8024, + 0x3b81, 0x8024, 0x3f04, 0xc024, 0x2808, 0x4800, 0x36f1, 0x9811, 0x36f3, + 0x0024, 0x3009, 0x3848, 0x3e14, 0x3811, 0x3e00, 0x0024, 0x0000, 0x4000, + 0x0001, 0x0010, 0x2915, 0x94c0, 0x0001, 0xcc11, 0x36f0, 0x0024, 0x2927, + 0x9e40, 0x3604, 0x1811, 0x3613, 0x0024, 0x3e14, 0x3811, 0x3e00, 0x0024, + 0x0000, 0x4000, 0x0001, 0x0010, 0x2915, 0x94c0, 0x0001, 0xcc11, 0x36f0, + 0x0024, 0x36f4, 0x1811, 0x3009, 0x1808, 0x2000, 0x0000, 0x0000, 0x190d, + 0x3600, 0x3840, 0x3e13, 0x780e, 0x3e13, 0xf808, 0x3e00, 0x0024, 0x0000, + 0x3fce, 0x0027, 0x9e0f, 0x2922, 0xb680, 0x0000, 0x190d, 0x36f3, 0x0024, + 0x36f3, 0xd808, 0x36f3, 0x580e, 0x2000, 0x0000, 0x3009, 0x1800, 0x3613, + 0x0024, 0x3e22, 0xb815, 0x3e05, 0xb814, 0x3615, 0x0024, 0x0000, 0x800a, + 0x3e13, 0x7801, 0x3e10, 0xb803, 0x3e11, 0x3805, 0x3e11, 0xb807, 0x3e14, + 0x3811, 0x3e14, 0xb813, 0x3e03, 0xf80e, 0xb488, 0x44d5, 0x3543, 0x134c, + 0x34e5, 0xc024, 0x3524, 0x8024, 0x35a4, 0xc024, 0x3710, 0x8a0c, 0x3540, + 0x4a0c, 0x3d44, 0x8024, 0x3a10, 0x8024, 0x3590, 0x0024, 0x4010, 0x15c1, + 0x6010, 0x3400, 0x3710, 0x8024, 0x2800, 0x5484, 0x3af0, 0x8024, 0x3df0, + 0x0024, 0x3591, 0x4024, 0x3530, 0x4024, 0x4192, 0x4050, 0x6100, 0x1482, + 0x4020, 0x1753, 0xbf8e, 0x1582, 0x4294, 0x4011, 0xbd86, 0x408e, 0x2400, + 0x528e, 0xfe6d, 0x2819, 0x520e, 0x0a00, 0x5207, 0x2819, 0x4fbe, 0x0024, + 0xad56, 0x904c, 0xaf5e, 0x1010, 0xf7d4, 0x0024, 0xf7fc, 0x2042, 0x6498, + 0x2046, 0x3cf4, 0x0024, 0x3400, 0x170c, 0x4090, 0x1492, 0x35a4, 0xc024, + 0x2800, 0x4d15, 0x3c00, 0x0024, 0x4480, 0x914c, 0x36f3, 0xd80e, 0x36f4, + 0x9813, 0x36f4, 0x1811, 0x36f1, 0x9807, 0x36f1, 0x1805, 0x36f0, 0x9803, + 0x36f3, 0x5801, 0x3405, 0x9014, 0x36e3, 0x0024, 0x2000, 0x0000, 0x36f2, + 0x9815, 0x2814, 0x9c91, 0x0000, 0x004d, 0x2814, 0x9940, 0x003f, 0x0013, + 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3625, 0x0024, 0x0000, + 0x800a, 0x3e10, 0x3801, 0x3e10, 0xb803, 0x3e11, 0x3805, 0x3e11, 0xb807, + 0x3e14, 0x3811, 0x0006, 0xa090, 0x2912, 0x0d00, 0x3e14, 0xc024, 0x4088, + 0x8000, 0x4080, 0x0024, 0x0007, 0x90d1, 0x2800, 0x5f85, 0x0000, 0x0024, + 0x0007, 0x9051, 0x3100, 0x4024, 0x4100, 0x0024, 0x3900, 0x0024, 0x0007, + 0x90d1, 0x0004, 0x0000, 0x31f0, 0x4024, 0x6014, 0x0400, 0x0000, 0x0024, + 0x2800, 0x63d1, 0x4080, 0x0024, 0x0000, 0x0000, 0x2800, 0x6345, 0x0000, + 0x0024, 0x0007, 0x9053, 0x3300, 0x0024, 0x4080, 0x0024, 0x0000, 0x0000, + 0x2800, 0x63d8, 0x0000, 0x0024, 0x0007, 0x9051, 0x3900, 0x0024, 0x3200, + 0x504c, 0x6410, 0x0024, 0x3cf0, 0x0000, 0x4080, 0x0024, 0x0006, 0xc691, + 0x2800, 0x7c85, 0x3009, 0x0400, 0x0000, 0x1001, 0x0007, 0x9051, 0x3100, + 0x0024, 0x6012, 0x0024, 0x0006, 0xc6d0, 0x2800, 0x70c9, 0x003f, 0xe000, + 0x0006, 0xc693, 0x3900, 0x0c00, 0x3009, 0x0001, 0x6014, 0x0024, 0x0007, + 0x1ad0, 0x2800, 0x70d5, 0x3009, 0x0000, 0x4080, 0x0024, 0x0000, 0x0301, + 0x2800, 0x6ac5, 0x4090, 0x0024, 0x0000, 0x0024, 0x2800, 0x6bd5, 0x0000, + 0x0024, 0x3009, 0x0000, 0xc012, 0x0024, 0x2800, 0x70c0, 0x3009, 0x2001, + 0x3009, 0x0000, 0x6012, 0x0024, 0x0000, 0x0341, 0x2800, 0x6dd5, 0x0000, + 0x0024, 0x6190, 0x0024, 0x2800, 0x70c0, 0x3009, 0x2000, 0x6012, 0x0024, + 0x0000, 0x0381, 0x2800, 0x6f95, 0x0000, 0x0024, 0x6190, 0x0024, 0x2800, + 0x70c0, 0x3009, 0x2000, 0x6012, 0x0024, 0x0000, 0x00c0, 0x2800, 0x70d5, + 0x0000, 0x0024, 0x3009, 0x2000, 0x0006, 0xa090, 0x3009, 0x0000, 0x4080, + 0x0024, 0x0000, 0x0081, 0x2800, 0x7595, 0x0007, 0x8c13, 0x3300, 0x104c, + 0xb010, 0x0024, 0x0002, 0x8001, 0x2800, 0x7805, 0x34f0, 0x0024, 0x2800, + 0x7580, 0x0000, 0x0024, 0x0006, 0xc351, 0x3009, 0x0000, 0x6090, 0x0024, + 0x3009, 0x2000, 0x2900, 0x0b80, 0x3009, 0x0405, 0x0006, 0xc6d1, 0x0006, + 0xc690, 0x3009, 0x0000, 0x3009, 0x0401, 0x6014, 0x0024, 0x0006, 0xa093, + 0x2800, 0x7411, 0xb880, 0x0024, 0x2800, 0x8540, 0x3009, 0x2c00, 0x4040, + 0x0024, 0x6012, 0x0024, 0x0006, 0xc6d0, 0x2800, 0x8558, 0x0000, 0x0024, + 0x0006, 0xc693, 0x3009, 0x0c00, 0x3009, 0x0001, 0x6014, 0x0024, 0x0006, + 0xc350, 0x2800, 0x8541, 0x0000, 0x0024, 0x6090, 0x0024, 0x3009, 0x2c00, + 0x3009, 0x0005, 0x2900, 0x0b80, 0x0000, 0x8548, 0x3009, 0x0400, 0x4080, + 0x0024, 0x0003, 0x8000, 0x2800, 0x8545, 0x0000, 0x0024, 0x6400, 0x0024, + 0x0000, 0x0081, 0x2800, 0x8549, 0x0000, 0x0024, 0x0007, 0x8c13, 0x3300, + 0x0024, 0xb010, 0x0024, 0x0006, 0xc650, 0x2800, 0x8555, 0x0000, 0x0024, + 0x0001, 0x0002, 0x3413, 0x0000, 0x3009, 0x0401, 0x4010, 0x8406, 0x0000, + 0x0281, 0xa010, 0x13c1, 0x4122, 0x0024, 0x0000, 0x03c2, 0x6122, 0x8002, + 0x462c, 0x0024, 0x469c, 0x0024, 0xfee2, 0x0024, 0x48be, 0x0024, 0x6066, + 0x8400, 0x0006, 0xc350, 0x2800, 0x8541, 0x0000, 0x0024, 0x4090, 0x0024, + 0x3009, 0x2400, 0x2900, 0x0b80, 0x3009, 0x0005, 0x0007, 0x1b50, 0x2912, + 0x0d00, 0x3613, 0x0024, 0x3a00, 0x0380, 0x4080, 0x0024, 0x0000, 0x00c1, + 0x2800, 0x8e05, 0x3009, 0x0000, 0xb010, 0x008c, 0x4192, 0x0024, 0x6012, + 0x0024, 0x0006, 0xf051, 0x2800, 0x8c18, 0x3009, 0x0400, 0x0007, 0x1fd1, + 0x30e3, 0x0400, 0x4080, 0x0024, 0x0000, 0x0301, 0x2800, 0x8e05, 0x3009, + 0x0000, 0xb010, 0x0024, 0x0000, 0x0101, 0x6012, 0x0024, 0x0006, 0xf051, + 0x2800, 0x8e15, 0x0000, 0x0024, 0x3023, 0x0400, 0xf200, 0x184c, 0xb880, + 0xa400, 0x3009, 0x2000, 0x3009, 0x0441, 0x3e10, 0x4402, 0x2909, 0xa9c0, + 0x3e10, 0x8024, 0x36e3, 0x0024, 0x36f4, 0xc024, 0x36f4, 0x1811, 0x36f1, + 0x9807, 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f0, 0x1801, 0x3405, 0x9014, + 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, + 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3635, 0x0024, + 0x0000, 0x800a, 0x3e10, 0x3801, 0x0000, 0x0081, 0x3e10, 0xb803, 0x3e11, + 0x3805, 0x3e11, 0xb807, 0x3e14, 0x3811, 0x0006, 0xf250, 0x3e04, 0xb813, + 0x3009, 0x0000, 0x6012, 0x0024, 0x003f, 0xff01, 0x2800, 0x9905, 0x0006, + 0x0611, 0x6194, 0x0400, 0x0000, 0x0041, 0xa020, 0x984c, 0x0000, 0x01c2, + 0xfe02, 0x0024, 0x48b2, 0x0024, 0x3e10, 0x0024, 0x2921, 0xca80, 0x3e00, + 0x4024, 0x3100, 0x5bcc, 0x2921, 0xdd40, 0xb122, 0x0024, 0x291a, 0x8a40, + 0x0000, 0xab08, 0x0007, 0x2052, 0x0006, 0x8a93, 0x3100, 0x184c, 0xa010, + 0x0024, 0x0000, 0x0041, 0x6090, 0x0024, 0x2922, 0x1880, 0x6090, 0x0024, + 0xb880, 0x010c, 0x3100, 0x2800, 0xfe02, 0x8c44, 0x3613, 0x0fc5, 0x4eb2, + 0x0024, 0x3009, 0x2040, 0x0000, 0x00c0, 0x2921, 0xbb80, 0x3e00, 0x23c1, + 0x0000, 0x01c1, 0x6012, 0x0024, 0x0003, 0xf680, 0x2800, 0x9f55, 0x0000, + 0x0024, 0x36f3, 0x0024, 0x291a, 0x8a40, 0x0000, 0xab08, 0x2900, 0x4580, + 0x3e00, 0x0024, 0x3413, 0x0040, 0x36f3, 0x03c1, 0x3009, 0x0c44, 0x3009, + 0x0fc5, 0x6ce2, 0x0024, 0x3c10, 0x0024, 0xbc82, 0x33c1, 0x3410, 0x2040, + 0x34e0, 0x63c1, 0x4c82, 0x0024, 0x0000, 0x0024, 0x2800, 0xa809, 0x4c82, + 0x0024, 0x0000, 0x01c4, 0x4c86, 0x184c, 0x003f, 0xff40, 0xad06, 0x0024, + 0x3e10, 0x8024, 0x2921, 0xca80, 0x3e00, 0xc024, 0x36f3, 0x0024, 0x2921, + 0x9440, 0x0000, 0x0080, 0xb88a, 0x104c, 0x3410, 0x0c46, 0x34e0, 0x4fc7, + 0xbce2, 0x984c, 0x4cf2, 0x0024, 0x3e10, 0x0024, 0x2921, 0x9780, 0x3e00, + 0x4024, 0x2800, 0xaa00, 0x36e3, 0x0024, 0x0000, 0x0024, 0x2800, 0xaa18, + 0x0000, 0x0024, 0x4ce6, 0x184c, 0x3e10, 0x8024, 0x2921, 0x9780, 0x3e00, + 0xc024, 0x36e3, 0x0024, 0x291a, 0x8a40, 0x0000, 0x0100, 0x2922, 0x1880, + 0x3613, 0x0024, 0x36f4, 0x9813, 0x36f4, 0x1811, 0x36f1, 0x9807, 0x36f1, + 0x1805, 0x36f0, 0x9803, 0x36f0, 0x1801, 0x3405, 0x9014, 0x36f3, 0x0024, + 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, 0x0024, 0x3e12, + 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3635, 0x0024, 0x0000, 0x800a, + 0x3e10, 0x7802, 0x3e14, 0x0024, 0x2903, 0x9bc0, 0x0000, 0x0201, 0x0000, + 0x0601, 0x3413, 0x184c, 0x2903, 0xa300, 0x3cf0, 0x0024, 0x3413, 0x184c, + 0x3400, 0x3040, 0x3009, 0x33c1, 0x0000, 0x1fc1, 0xb010, 0x0024, 0x6014, + 0x9040, 0x0006, 0x8010, 0x2800, 0xb495, 0x0000, 0x0024, 0x34e3, 0x1bcc, + 0x6890, 0x0024, 0x2800, 0xb640, 0xb880, 0x2000, 0x3e10, 0x1381, 0x2903, + 0xd400, 0x3e00, 0x4024, 0x003f, 0xfe41, 0x36e3, 0x104c, 0x34f0, 0x0024, + 0xa010, 0x0024, 0x36f4, 0x0024, 0x36f0, 0x5802, 0x3405, 0x9014, 0x36f3, + 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x0006, 0x9f97, + 0x3e00, 0x5c15, 0x3009, 0x3840, 0x3009, 0x3814, 0x0025, 0xffd4, 0x0006, + 0xd317, 0x3710, 0x160c, 0x0006, 0x9f94, 0x37f0, 0x73d5, 0x6c92, 0x0024, + 0x3f10, 0x1040, 0x3ff0, 0x53c1, 0x6010, 0x0024, 0x0000, 0x0024, 0x2800, + 0xbc54, 0x0006, 0x0001, 0x4010, 0x0024, 0x0005, 0xf601, 0x6010, 0x9bd4, + 0x0000, 0x0040, 0x2800, 0xbdd4, 0x0030, 0x0497, 0x3f00, 0x0024, 0x2000, + 0x0000, 0x36f0, 0x5800, 0x2a08, 0x1b8e, 0x2803, 0xae80, 0x0000, 0xbe57, + 0x0007, 0x0001, /*copy 1*/ + 0x8300, 0x0006, 0x19f8, /*copy 6648*/ + 0x0030, 0x0055, 0xb080, 0x1402, 0x0fdf, 0xffc1, 0x0007, 0x9257, 0xb212, + 0x3c00, 0x3d00, 0x4024, 0x0006, 0x0097, 0x3f10, 0x0024, 0x3f00, 0x0024, + 0x0030, 0x0297, 0x3f00, 0x0024, 0x0007, 0x9017, 0x3f00, 0x0024, 0x0007, + 0x81d7, 0x3f10, 0x0024, 0xc090, 0x3c00, 0x0006, 0x0297, 0xb080, 0x3c00, + 0x0000, 0x0401, 0x000a, 0x1055, 0x0006, 0x0017, 0x3f10, 0x3401, 0x000a, + 0x2795, 0x3f00, 0x3401, 0x0001, 0x6257, 0xf400, 0x55c0, 0x0000, 0x0817, + 0xb080, 0x57c0, 0x0014, 0x958f, 0x0000, 0x58ce, 0x0030, 0x0017, 0x3700, + 0x0024, 0x0004, 0x0001, 0xb012, 0x0024, 0x0000, 0x004d, 0x280f, 0xe115, + 0x0006, 0x2016, 0x0006, 0x01d7, 0x3f00, 0x0024, 0x0000, 0x190d, 0x000f, + 0xf94f, 0x0000, 0xcd0e, 0x280f, 0xe100, 0x0006, 0x2016, 0x0000, 0x0080, + 0x0005, 0x4f92, 0x2909, 0xf840, 0x3613, 0x2800, 0x0006, 0x0197, 0x0006, + 0xa115, 0xb080, 0x0024, 0x3f00, 0x3400, 0x0007, 0x8a57, 0x3700, 0x0024, + 0x4080, 0x0024, 0x0000, 0x0040, 0x2800, 0xced5, 0x0006, 0xa2d7, 0x3009, + 0x3c00, 0x0006, 0xa157, 0x3009, 0x1c00, 0x0006, 0x01d7, 0x0000, 0x190d, + 0x000a, 0x708f, 0x0000, 0xd7ce, 0x290b, 0x1a80, 0x3f00, 0x184c, 0x0030, + 0x0017, 0x4080, 0x1c01, 0x0000, 0x0200, 0x2800, 0xcb15, 0xb102, 0x0024, + 0x0000, 0xcd08, 0x2800, 0xcb15, 0x0000, 0xd3ce, 0x0011, 0x210f, 0x0000, + 0x190d, 0x280f, 0xcb00, 0x3613, 0x0024, 0x0006, 0xa115, 0x0006, 0x01d7, + 0x37f0, 0x1401, 0x6100, 0x1c01, 0x4012, 0x0024, 0x0000, 0x8000, 0x6010, + 0x0024, 0x34f3, 0x0400, 0x2800, 0xd698, 0x0000, 0x0024, 0x0000, 0x8001, + 0x6010, 0x3c01, 0x0000, 0x000d, 0x2811, 0x8259, 0x0000, 0x0024, 0x2a11, + 0x2100, 0x0030, 0x0257, 0x3700, 0x0024, 0x4080, 0x0024, 0x0000, 0x0024, + 0x2800, 0xd9d5, 0x0006, 0x0197, 0x0006, 0xa115, 0x3f00, 0x3400, 0x4d86, + 0x0024, 0x0000, 0x190d, 0x2800, 0xdd55, 0x0014, 0x1b01, 0x0020, 0x480f, + 0x0000, 0xdc0e, 0x0000, 0x190d, 0x2820, 0x41c0, 0x0001, 0x0948, 0x0039, + 0x324f, 0x0001, 0x364e, 0x2820, 0x4a18, 0xb882, 0x0024, 0x2a20, 0x48c0, + 0x003f, 0xfd00, 0xb700, 0x0024, 0x003f, 0xf901, 0x6010, 0x0024, 0x0000, + 0x0024, 0x280a, 0xc505, 0x0000, 0x190d, 0x0019, 0x9301, 0x2800, 0xdfc0, + 0x0018, 0x50c0, 0x6fc2, 0x0024, 0x0000, 0x0024, 0x2800, 0xe155, 0x0000, + 0x0024, 0x2803, 0x5840, 0x000a, 0xcac8, 0x000a, 0x8c8f, 0x0000, 0xe28e, + 0x000c, 0x0981, 0x280a, 0x71c0, 0x002c, 0x9d40, 0x000a, 0x708f, 0x0000, + 0xd7ce, 0x280a, 0xc0d5, 0x0012, 0x5182, 0x6fd6, 0x0024, 0x003f, 0xfd81, + 0x280a, 0x8e45, 0xb710, 0x0024, 0x003f, 0xf800, 0xb600, 0x0024, 0x0015, + 0xb801, 0x6012, 0x0024, 0x003f, 0xfd81, 0x2801, 0xbac5, 0x0001, 0x0a48, + 0xb710, 0x0024, 0x003f, 0xfc01, 0x6012, 0x0024, 0x0000, 0x0101, 0x2801, + 0x0015, 0xffd2, 0x0024, 0x48b2, 0x0024, 0x4190, 0x0024, 0x0000, 0x190d, + 0x2801, 0x0015, 0x0030, 0x0250, 0xb880, 0x104c, 0x3cf0, 0x0024, 0x0010, + 0x5500, 0xb880, 0x23c0, 0xb882, 0x2000, 0x0007, 0x8590, 0x2914, 0xbec0, + 0x0000, 0x0440, 0x0007, 0x8b50, 0xb880, 0x0024, 0x2920, 0x0100, 0x3800, + 0x0024, 0x2920, 0x0000, 0x0006, 0x8a91, 0x0000, 0x0800, 0xb880, 0xa440, + 0x003f, 0xfd81, 0xb710, 0xa7c0, 0x003f, 0xfc01, 0x6012, 0x0024, 0x0000, + 0x0101, 0x2801, 0x0955, 0x0000, 0x0024, 0xffe2, 0x0024, 0x48b2, 0x0024, + 0x4190, 0x0024, 0x0000, 0x0024, 0x2801, 0x0955, 0x0000, 0x0024, 0x2912, + 0x2d80, 0x0000, 0x0780, 0x4080, 0x0024, 0x0006, 0x8a90, 0x2801, 0x0955, + 0x0000, 0x01c2, 0xb886, 0x8040, 0x3613, 0x03c1, 0xbcd2, 0x0024, 0x0030, + 0x0011, 0x2800, 0xf5d5, 0x003f, 0xff42, 0xb886, 0x8040, 0x3009, 0x03c1, + 0x0000, 0x0020, 0xac22, 0x0024, 0x0000, 0x0102, 0x6cd2, 0x0024, 0x3e10, + 0x0024, 0x2909, 0x8c80, 0x3e00, 0x4024, 0x36f3, 0x0024, 0x3e11, 0x8024, + 0x3e01, 0xc024, 0x2901, 0x2d00, 0x0000, 0x0201, 0xf400, 0x4512, 0x2900, + 0x0c80, 0x3213, 0x1b8c, 0x3100, 0x0024, 0xb010, 0x0024, 0x0000, 0x0024, + 0x2801, 0x0955, 0x0000, 0x0024, 0x291a, 0x8a40, 0x0000, 0x0100, 0x2920, + 0x0200, 0x3633, 0x0024, 0x2920, 0x0280, 0x0000, 0x0401, 0x408e, 0x0024, + 0x2920, 0x0280, 0x0000, 0x0401, 0x003f, 0xfd81, 0xb710, 0x4006, 0x003f, + 0xfc01, 0x6012, 0x0024, 0x0000, 0x0101, 0x2801, 0x0955, 0x0000, 0x0024, + 0xffe2, 0x0024, 0x48b2, 0x0024, 0x4190, 0x0024, 0x0000, 0x0024, 0x2801, + 0x0955, 0x0000, 0x0024, 0x2912, 0x2d80, 0x0000, 0x0780, 0x4080, 0x0024, + 0x0000, 0x01c2, 0x2800, 0xf1c5, 0x0006, 0x8a90, 0x2a01, 0x0940, 0x2920, + 0x0100, 0x0000, 0x0401, 0x0000, 0x0180, 0x2920, 0x0200, 0x3613, 0x0024, + 0x2920, 0x0280, 0x3613, 0x0024, 0x0000, 0x0401, 0x2920, 0x0280, 0x4084, + 0x984c, 0x0019, 0x9d01, 0x6212, 0x0024, 0x001e, 0x5c01, 0x2801, 0x0495, + 0x6012, 0x0024, 0x0000, 0x0024, 0x2801, 0x0685, 0x0000, 0x0024, 0x001b, + 0x5bc1, 0x6212, 0x0024, 0x001b, 0xdd81, 0x2801, 0x0a55, 0x6012, 0x0024, + 0x0000, 0x0024, 0x2801, 0x0a55, 0x0000, 0x0024, 0x0000, 0x004d, 0x000a, + 0xbf4f, 0x280a, 0xb880, 0x0001, 0x078e, 0x0020, 0xfb4f, 0x0000, 0x190d, + 0x0001, 0x0e8e, 0x2920, 0xf440, 0x3009, 0x2bc1, 0x291a, 0x8a40, 0x36e3, + 0x0024, 0x0000, 0x190d, 0x000a, 0x708f, 0x280a, 0xcac0, 0x0000, 0xd7ce, + 0x0030, 0x0017, 0x3700, 0x4024, 0x0000, 0x0200, 0xb102, 0x0024, 0x0000, + 0x00c0, 0x2801, 0x0d85, 0x0005, 0x4f92, 0x2909, 0xf840, 0x3613, 0x2800, + 0x0006, 0x0197, 0x0006, 0xa115, 0xb080, 0x0024, 0x3f00, 0x3400, 0x0000, + 0x190d, 0x000a, 0x708f, 0x280a, 0xc0c0, 0x0000, 0xd7ce, 0x0000, 0x004d, + 0x0020, 0xfe0f, 0x2820, 0xfb40, 0x0001, 0x0f8e, 0x2801, 0x1155, 0x3009, + 0x1000, 0x6012, 0x93cc, 0x0000, 0x0024, 0x2801, 0x2c05, 0x0000, 0x0024, + 0x3413, 0x0024, 0x34b0, 0x0024, 0x4080, 0x0024, 0x0000, 0x0200, 0x2801, + 0x1455, 0xb882, 0x0024, 0x3453, 0x0024, 0x3009, 0x13c0, 0x4080, 0x0024, + 0x0000, 0x0200, 0x2801, 0x2c05, 0x0000, 0x0024, 0xb882, 0x130c, 0x0000, + 0x004d, 0x0021, 0x058f, 0x2821, 0x0340, 0x0001, 0x154e, 0x2801, 0x2595, + 0x6012, 0x0024, 0x0000, 0x0024, 0x2801, 0x2595, 0x0000, 0x0024, 0x34c3, + 0x184c, 0x3e13, 0xb80f, 0xf400, 0x4500, 0x0026, 0x9dcf, 0x0001, 0x194e, + 0x0000, 0xfa0d, 0x2926, 0x8e80, 0x3e10, 0x110c, 0x36f3, 0x0024, 0x2801, + 0x2580, 0x36f3, 0x980f, 0x001c, 0xdd00, 0x001c, 0xd901, 0x6ec2, 0x0024, + 0x001c, 0xdd00, 0x2801, 0x1c55, 0x0018, 0xdbc1, 0x3413, 0x184c, 0xf400, + 0x4500, 0x2926, 0xc640, 0x3e00, 0x13cc, 0x2801, 0x2340, 0x36f3, 0x0024, + 0x6ec2, 0x0024, 0x003f, 0xc000, 0x2801, 0x1ed5, 0x002a, 0x4001, 0x3413, + 0x184c, 0xf400, 0x4500, 0x2926, 0xafc0, 0x3e00, 0x13cc, 0x2801, 0x2340, + 0x36f3, 0x0024, 0xb400, 0x0024, 0xd100, 0x0024, 0x0000, 0x0024, 0x2801, + 0x2345, 0x0000, 0x0024, 0x3613, 0x0024, 0x3e11, 0x4024, 0x2926, 0x8540, + 0x3e01, 0x0024, 0x4080, 0x1b8c, 0x0000, 0x0024, 0x2801, 0x2345, 0x0000, + 0x0024, 0x3413, 0x184c, 0xf400, 0x4500, 0x2926, 0x8e80, 0x3e10, 0x13cc, + 0x36f3, 0x0024, 0x3110, 0x8024, 0x31f0, 0xc024, 0x0000, 0x4000, 0x0000, + 0x0021, 0x6d06, 0x0024, 0x3110, 0x8024, 0x2826, 0xa8c4, 0x31f0, 0xc024, + 0x2a26, 0xad00, 0x34c3, 0x184c, 0x3410, 0x8024, 0x3430, 0xc024, 0x0000, + 0x4000, 0x0000, 0x0021, 0x6d06, 0x0024, 0x0000, 0x0024, 0x2801, 0x2c14, + 0x4d06, 0x0024, 0x0000, 0x0200, 0x2922, 0x1885, 0x0001, 0x2a88, 0x0000, + 0x0200, 0x3e10, 0x8024, 0x2921, 0xca80, 0x3e00, 0xc024, 0x291a, 0x8a40, + 0x0000, 0x0024, 0x2922, 0x1880, 0x36f3, 0x0024, 0x0000, 0x004d, 0x0021, + 0x0ecf, 0x2821, 0x0bc0, 0x0001, 0x2b8e, 0x2801, 0x0e80, 0x3c30, 0x4024, + 0x0000, 0x190d, 0x0000, 0x3fce, 0x2821, 0x0f80, 0x0027, 0x9e0f, 0x0020, + 0xcd4f, 0x2820, 0xc780, 0x0001, 0x2dce, 0x0006, 0xf017, 0x0000, 0x0015, + 0xb070, 0xbc15, 0x0000, 0x3fce, 0x0027, 0x9e0f, 0x2820, 0xcd80, 0x0000, + 0x190d, 0x3613, 0x0024, 0x3e10, 0xb803, 0x3e14, 0x3811, 0x3e11, 0x3805, + 0x3e00, 0x3801, 0x0007, 0xc390, 0x0006, 0xa011, 0x3010, 0x0444, 0x3050, + 0x4405, 0x6458, 0x0302, 0xff94, 0x4081, 0x0003, 0xffc5, 0x48b6, 0x0024, + 0xff82, 0x0024, 0x42b2, 0x0042, 0xb458, 0x0003, 0x4cd6, 0x9801, 0xf248, + 0x1bc0, 0xb58a, 0x0024, 0x6de6, 0x1804, 0x0006, 0x0010, 0x3810, 0x9bc5, + 0x3800, 0xc024, 0x36f4, 0x1811, 0x36f0, 0x9803, 0x283e, 0x2d80, 0x0fff, + 0xffc3, 0x2801, 0x4400, 0x0000, 0x0024, 0x3413, 0x0024, 0x2801, 0x3805, + 0xf400, 0x4517, 0x2801, 0x3c00, 0x6894, 0x13cc, 0x37b0, 0x184c, 0x6090, + 0x1d51, 0x0000, 0x0910, 0x3f00, 0x060c, 0x3100, 0x4024, 0x6016, 0xb812, + 0x000c, 0x8012, 0x2801, 0x3a91, 0xb884, 0x0024, 0x6894, 0x3002, 0x0000, + 0x028d, 0x003a, 0x5e0f, 0x0001, 0x4c0e, 0x2939, 0xb0c0, 0x3e10, 0x93cc, + 0x4084, 0x9bd2, 0x4282, 0x0024, 0x0000, 0x0040, 0x2801, 0x3e05, 0x4292, + 0x130c, 0x3443, 0x0024, 0x2801, 0x3f45, 0x000c, 0x8390, 0x2a01, 0x42c0, + 0x3444, 0x0024, 0x3073, 0x0024, 0xc090, 0x014c, 0x2801, 0x42c0, 0x3800, + 0x0024, 0x000c, 0x4113, 0xb880, 0x2380, 0x3304, 0x4024, 0x3800, 0x05cc, + 0xcc92, 0x05cc, 0x3910, 0x0024, 0x3910, 0x4024, 0x000c, 0x8110, 0x3910, + 0x0024, 0x39f0, 0x4024, 0x3810, 0x0024, 0x38d0, 0x4024, 0x3810, 0x0024, + 0x38f0, 0x4024, 0x34c3, 0x0024, 0x3444, 0x0024, 0x3073, 0x0024, 0x3063, + 0x0024, 0x3000, 0x0024, 0x4080, 0x0024, 0x0000, 0x0024, 0x2839, 0x53d5, + 0x4284, 0x0024, 0x3613, 0x0024, 0x2801, 0x4605, 0x6898, 0xb804, 0x0000, + 0x0084, 0x293b, 0x1cc0, 0x3613, 0x0024, 0x000c, 0x8117, 0x3711, 0x0024, + 0x37d1, 0x4024, 0x4e8a, 0x0024, 0x0000, 0x0015, 0x2801, 0x48c5, 0xce9a, + 0x0024, 0x3f11, 0x0024, 0x3f01, 0x4024, 0x000c, 0x8197, 0x408a, 0x9bc4, + 0x3f15, 0x4024, 0x2801, 0x4b05, 0x4284, 0x3c15, 0x6590, 0x0024, 0x0000, + 0x0024, 0x2839, 0x53d5, 0x4284, 0x0024, 0x0000, 0x0024, 0x2801, 0x36d8, + 0x458a, 0x0024, 0x2a39, 0x53c0, 0x003e, 0x2d4f, 0x283a, 0x5ed5, 0x0001, + 0x2f8e, 0x000c, 0x4653, 0x0000, 0x0246, 0xffac, 0x0c01, 0x48be, 0x0024, + 0x4162, 0x4546, 0x6642, 0x4055, 0x3501, 0x8024, 0x0000, 0x0087, 0x667c, + 0x4057, 0x000c, 0x41d5, 0x283a, 0x62d5, 0x3501, 0x8024, 0x667c, 0x1c47, + 0x3701, 0x8024, 0x283a, 0x62d5, 0xc67c, 0x0024, 0x0000, 0x0024, 0x283a, + 0x62c5, 0x0000, 0x0024, 0x2a3a, 0x5ec0, 0x3009, 0x3851, 0x3e14, 0xf812, + 0x3e12, 0xb817, 0x3e11, 0x8024, 0x0006, 0x0293, 0x3301, 0x8024, 0x468c, + 0x3804, 0x0006, 0xa057, 0x2801, 0x5804, 0x0006, 0x0011, 0x469c, 0x0024, + 0x3be1, 0x8024, 0x2801, 0x5815, 0x0006, 0xc392, 0x3311, 0x0024, 0x33f1, + 0x2844, 0x3009, 0x2bc4, 0x0030, 0x04d2, 0x3311, 0x0024, 0x3a11, 0x0024, + 0x3201, 0x8024, 0x003f, 0xfc04, 0xb64c, 0x0fc4, 0xc648, 0x0024, 0x3a01, + 0x0024, 0x3111, 0x1fd3, 0x6498, 0x07c6, 0x868c, 0x2444, 0x0023, 0xffd2, + 0x3901, 0x8e06, 0x0030, 0x0551, 0x3911, 0x8e06, 0x3961, 0x9c44, 0xf400, + 0x44c6, 0xd46c, 0x1bc4, 0x36f1, 0xbc13, 0x2801, 0x6195, 0x36f2, 0x9817, + 0x002b, 0xffd2, 0x3383, 0x188c, 0x3e01, 0x8c06, 0x0006, 0xa097, 0x3009, + 0x1c12, 0x3213, 0x0024, 0x468c, 0xbc12, 0x002b, 0xffd2, 0xf400, 0x4197, + 0x2801, 0x5e84, 0x3713, 0x0024, 0x2801, 0x5ec5, 0x37e3, 0x0024, 0x3009, + 0x2c17, 0x3383, 0x0024, 0x3009, 0x0c06, 0x468c, 0x4197, 0x0006, 0xa052, + 0x2801, 0x60c4, 0x3713, 0x2813, 0x2801, 0x6105, 0x37e3, 0x0024, 0x3009, + 0x2c17, 0x36f1, 0x8024, 0x36f2, 0x9817, 0x36f4, 0xd812, 0x2100, 0x0000, + 0x3904, 0x5bd1, 0x2a01, 0x51ce, 0x3e11, 0x7804, 0x0030, 0x0257, 0x3701, + 0x0024, 0x0013, 0x4d05, 0xd45b, 0xe0e1, 0x0007, 0xc795, 0x2801, 0x6915, + 0x0fff, 0xff45, 0x3511, 0x184c, 0x4488, 0xb808, 0x0006, 0x8a97, 0x2801, + 0x68c5, 0x3009, 0x1c40, 0x3511, 0x1fc1, 0x0000, 0x0020, 0xac52, 0x1405, + 0x6ce2, 0x0024, 0x0000, 0x0024, 0x2801, 0x68c1, 0x68c2, 0x0024, 0x291a, + 0x8a40, 0x3e10, 0x0024, 0x2921, 0xca80, 0x3e00, 0x4024, 0x36f3, 0x0024, + 0x3009, 0x1bc8, 0x36f0, 0x1801, 0x3601, 0x5804, 0x3e13, 0x780f, 0x3e13, + 0xb808, 0x0008, 0x9b0f, 0x0001, 0x6bce, 0x2908, 0x9300, 0x0000, 0x004d, + 0x36f3, 0x9808, 0x2000, 0x0000, 0x36f3, 0x580f, 0x0007, 0x81d7, 0x3711, + 0x8024, 0x3711, 0xc024, 0x3700, 0x0024, 0x0000, 0x2001, 0xb012, 0x0024, + 0x0034, 0x0000, 0x2801, 0x6f05, 0x0000, 0x01c1, 0x0030, 0x0117, 0x3f00, + 0x0024, 0x0014, 0xc000, 0x0000, 0x01c1, 0x4fce, 0x0024, 0xffea, 0x0024, + 0x48b6, 0x0024, 0x4384, 0x4097, 0xb886, 0x45c6, 0xfede, 0x0024, 0x4db6, + 0x0024, 0x466c, 0x0024, 0x0006, 0xc610, 0x8dd6, 0x8007, 0x0000, 0x00c6, + 0xff6e, 0x0024, 0x48b2, 0x0024, 0x0034, 0x2406, 0xffee, 0x0024, 0x2914, + 0xaa80, 0x40b2, 0x0024, 0xf1c6, 0x0024, 0xf1d6, 0x0024, 0x0000, 0x0201, + 0x8d86, 0x0024, 0x61de, 0x0024, 0x0006, 0xc612, 0x2801, 0x7581, 0x0006, + 0xc713, 0x4c86, 0x0024, 0x2912, 0x1180, 0x0006, 0xc351, 0x0006, 0x0210, + 0x2912, 0x0d00, 0x3810, 0x984c, 0xf200, 0x2043, 0x2808, 0xa000, 0x3800, + 0x0024, 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, + 0x3615, 0x0024, 0x0000, 0x800a, 0x3e10, 0x7802, 0x3e10, 0xf804, 0x3e11, + 0x7810, 0x3e14, 0x7812, 0x3e14, 0xc024, 0x2922, 0x1880, 0x0000, 0x0180, + 0x2921, 0xdd40, 0x6892, 0x184c, 0x4080, 0x0024, 0x0000, 0x0024, 0x2801, + 0x7cc5, 0x0000, 0x0024, 0x2801, 0xb840, 0xb880, 0x0024, 0x2921, 0xdd40, + 0x6892, 0x184c, 0x4080, 0x0024, 0x0000, 0x0181, 0x2801, 0x7ed5, 0x0000, + 0x0024, 0x2801, 0xb840, 0xb880, 0x0024, 0x2921, 0xdd40, 0x3613, 0x0024, + 0x4080, 0x0024, 0x0000, 0x0101, 0x2801, 0x80c5, 0x0000, 0x0024, 0x2801, + 0xb840, 0xb880, 0x0024, 0x2921, 0xdd40, 0x3613, 0x0024, 0x4080, 0x0024, + 0x0000, 0x00c1, 0x2801, 0x82c5, 0x0000, 0x0024, 0x2801, 0xb840, 0xb880, + 0x0024, 0x2921, 0xdd40, 0x3613, 0x0024, 0x4080, 0x0024, 0x0000, 0x0141, + 0x2801, 0x84c5, 0x0006, 0xf250, 0x2801, 0xb840, 0xb880, 0x0024, 0x2921, + 0xdd40, 0x3613, 0x0024, 0x0000, 0x0101, 0x2921, 0xdd40, 0x3613, 0x2000, + 0x0000, 0x03c1, 0x6012, 0x03cc, 0x3613, 0x2000, 0x2801, 0x8a15, 0x0006, + 0xf051, 0x3009, 0x3841, 0x2921, 0xdd40, 0x0000, 0x0201, 0xb080, 0x024c, + 0x3009, 0x2000, 0x2921, 0xdd40, 0x0000, 0x0401, 0x3009, 0x0401, 0xc100, + 0x0024, 0x2801, 0x8b40, 0x3009, 0x2400, 0x3009, 0x0002, 0x2920, 0x5d00, + 0x3e00, 0x8024, 0x36f3, 0x024c, 0x3009, 0x2000, 0x0000, 0x0101, 0x2921, + 0xdd40, 0x3613, 0x0024, 0x0000, 0x0141, 0x3013, 0x0024, 0x3009, 0x21c0, + 0x3009, 0x0000, 0x6012, 0x0024, 0x0007, 0x1b51, 0x2801, 0x9c95, 0x0000, + 0x0101, 0x0007, 0xc251, 0x2921, 0xdd40, 0x3613, 0x0024, 0x0000, 0x03c1, + 0x6012, 0x2400, 0x3100, 0x984c, 0x2801, 0x93d5, 0x0007, 0xc292, 0x3009, + 0x3841, 0x2921, 0xdd40, 0x0000, 0x0201, 0x4082, 0x044c, 0xb080, 0x0024, + 0x3910, 0x0024, 0x39f0, 0x7841, 0x2921, 0xdd40, 0x0000, 0x0401, 0x3211, + 0x1bcc, 0xb182, 0x0bc5, 0xcec2, 0x0024, 0x3a10, 0x0024, 0x2801, 0x9500, + 0x3af0, 0x4024, 0x2920, 0x5d00, 0x3e00, 0x8024, 0x36f3, 0x044c, 0x3910, + 0x0024, 0x39f0, 0x4024, 0x0007, 0x1b52, 0x0000, 0x0141, 0x2921, 0xdd40, + 0x3613, 0x0024, 0x3111, 0x2240, 0xb880, 0x03cc, 0x31f1, 0x6800, 0xb182, + 0x8000, 0x6ce6, 0x0024, 0x002e, 0xe002, 0x2801, 0xa385, 0xb886, 0x0024, + 0x6de2, 0x0b8c, 0x0000, 0x00c1, 0x2801, 0x9b51, 0x3009, 0x0800, 0xb010, + 0x0024, 0x4192, 0x0024, 0x6012, 0x0024, 0x0007, 0x1b52, 0x2801, 0x9b58, + 0x0000, 0x0024, 0x6890, 0xa004, 0x2801, 0xa380, 0x3009, 0x2800, 0x4e82, + 0x0024, 0x0000, 0x0020, 0xf2c2, 0x0024, 0x2801, 0xa380, 0x3009, 0x2000, + 0x3009, 0x07c0, 0x4080, 0x0024, 0x0000, 0x0024, 0x2801, 0xa385, 0x0000, + 0x0024, 0x3093, 0x0400, 0x4080, 0x03cc, 0x0017, 0x7001, 0x2801, 0xa295, + 0x3009, 0x0000, 0x6012, 0x0024, 0x0007, 0x1b50, 0x2801, 0xa201, 0xb880, + 0x0024, 0x0000, 0x00c1, 0x31f3, 0x0024, 0x3009, 0x0400, 0xb010, 0x0024, + 0x4080, 0x0024, 0x0000, 0x0000, 0x2801, 0xa289, 0x0000, 0x0024, 0x2801, + 0xa380, 0x3009, 0x2000, 0x0006, 0xf050, 0x3009, 0x0000, 0x4000, 0x0024, + 0x3009, 0x2000, 0x0000, 0x0081, 0x0006, 0xf250, 0x3009, 0x0000, 0x6012, + 0x0024, 0x0007, 0xc151, 0x2801, 0xa5c5, 0x0000, 0x0024, 0x2801, 0xb840, + 0xb880, 0x0024, 0x2921, 0xdd40, 0x6892, 0x184c, 0x6892, 0x2400, 0x2921, + 0xdd40, 0x3009, 0x184c, 0x4080, 0x0024, 0x0000, 0x0381, 0x2801, 0xa885, + 0x0000, 0x0024, 0x2921, 0xdd40, 0x3613, 0x0024, 0x2921, 0xdd40, 0x6892, + 0x184c, 0x4080, 0x0024, 0x0000, 0x0240, 0x2801, 0xab05, 0x0000, 0x00c1, + 0x2921, 0xdd40, 0x6892, 0x184c, 0x0000, 0x00c1, 0x0000, 0x0240, 0x0006, + 0x0592, 0x2922, 0x1880, 0x3613, 0x0024, 0x2921, 0xdd40, 0x3613, 0x0024, + 0x4080, 0x2800, 0x0000, 0x0201, 0x2801, 0xae15, 0x3613, 0x0024, 0x2921, + 0xdd40, 0x0001, 0xb088, 0x3613, 0x0024, 0x4090, 0x1bcc, 0x0000, 0x0241, + 0x2801, 0xb015, 0x0006, 0x0613, 0x2921, 0xdd40, 0x3613, 0x0024, 0x2801, + 0xb080, 0x3b00, 0x0024, 0x2801, 0xb840, 0xb880, 0x0024, 0x0006, 0x0653, + 0xb880, 0x184c, 0x2921, 0xdd40, 0x6892, 0x2c00, 0x4080, 0x0024, 0x0006, + 0x0650, 0x2801, 0xb605, 0x0000, 0x4003, 0x3000, 0x184c, 0xff86, 0x0024, + 0x48b6, 0x0024, 0x2921, 0xdd40, 0x6892, 0x2002, 0x0000, 0x0201, 0x2921, + 0xdd40, 0x4088, 0x184c, 0x3000, 0x4024, 0x4100, 0x0024, 0x4488, 0x2000, + 0x0000, 0x4003, 0x2801, 0xb295, 0x0006, 0x0650, 0x2921, 0xdd40, 0x6892, + 0x184c, 0x4080, 0x0024, 0x0000, 0x0201, 0x2801, 0xb805, 0x0000, 0x0024, + 0x2921, 0xdd40, 0x3613, 0x0024, 0x6890, 0x0024, 0x36f4, 0xc024, 0x36f4, + 0x5812, 0x36f1, 0x5810, 0x36f0, 0xd804, 0x36f0, 0x5802, 0x3405, 0x9014, + 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, + 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3635, 0x0024, + 0x0000, 0x800a, 0x3e10, 0x7802, 0x3e10, 0xf804, 0x3e14, 0x3811, 0x0006, + 0x8a91, 0x0006, 0x05d0, 0x3e14, 0xb813, 0x0007, 0x8b52, 0x3e13, 0xf80e, + 0x3e03, 0x504c, 0xb880, 0x0024, 0x3c00, 0x33c0, 0x2921, 0xb380, 0x3800, + 0x0024, 0x2920, 0x6a00, 0x0030, 0x0253, 0x0000, 0x0400, 0xb882, 0xa440, + 0xb880, 0xa7c1, 0x3a00, 0x0024, 0x0013, 0x1040, 0x3b00, 0x0024, 0x0000, + 0x0180, 0x2922, 0x1880, 0x3613, 0x0024, 0x4f82, 0x0024, 0x003f, 0xf801, + 0xb010, 0x0024, 0x0015, 0xb801, 0x6012, 0x0024, 0x0007, 0x8a50, 0x2801, + 0xdfd5, 0x0000, 0x0201, 0x0006, 0x8a90, 0x2921, 0xdd40, 0x3613, 0x0024, + 0x003f, 0xfe00, 0x3613, 0x0042, 0xb882, 0x83c3, 0xbdc2, 0x0024, 0x3009, + 0x2040, 0x2921, 0xdd40, 0x6892, 0xa3c1, 0x4080, 0x0024, 0x0000, 0x0024, + 0x2801, 0xca95, 0x0000, 0x0024, 0x2901, 0x7780, 0x0006, 0x05d1, 0x4080, + 0x2400, 0x0006, 0xf052, 0x2801, 0xca85, 0x0000, 0x0024, 0x3613, 0x0841, + 0x3e10, 0x4802, 0x2909, 0xa9c0, 0x3e10, 0x8024, 0x36e3, 0x0024, 0x0006, + 0x05d1, 0x3100, 0x0024, 0x4080, 0x0024, 0x0000, 0x0024, 0x2921, 0xc305, + 0x0001, 0xdb48, 0x0006, 0x0592, 0xb880, 0x104c, 0x3613, 0x33c0, 0x2922, + 0x1880, 0x0000, 0x0100, 0x3200, 0x0024, 0x4080, 0x0024, 0x0000, 0x0024, + 0x2900, 0x90d5, 0x0001, 0xd3c8, 0x0006, 0x0613, 0xb880, 0x0024, 0x0006, + 0x0610, 0x3b00, 0x0024, 0x0000, 0x0201, 0x2921, 0xdd40, 0x3613, 0x0024, + 0x0000, 0x00c1, 0x3423, 0x0024, 0x3c00, 0x0024, 0xa010, 0x0001, 0x4100, + 0x0024, 0x0000, 0x3fc1, 0x3800, 0x0024, 0x34e0, 0x0024, 0x6012, 0x0024, + 0x0006, 0x0610, 0x2801, 0xcf85, 0x0000, 0x0024, 0x2900, 0x90c0, 0x0000, + 0x0024, 0x0006, 0x0650, 0x3000, 0x0024, 0x4080, 0x0024, 0x0000, 0x0024, + 0x2801, 0xdac5, 0x0000, 0x0024, 0xf200, 0x184c, 0xf200, 0x0024, 0xf200, + 0x0024, 0xb182, 0x3840, 0x2921, 0xca80, 0x3e00, 0x4024, 0x0000, 0x01c1, + 0x291a, 0x8a40, 0x36e3, 0x0024, 0xb888, 0x4411, 0x3000, 0x0024, 0xb012, + 0x0024, 0x6410, 0x2001, 0x0000, 0x0024, 0x2801, 0xdac1, 0x0000, 0x0024, + 0x4192, 0x0024, 0x2401, 0xda81, 0x0000, 0x0024, 0x2921, 0xdd40, 0x6892, + 0x184c, 0x6498, 0x0024, 0x2921, 0xc300, 0x0000, 0x0024, 0x291a, 0x8a40, + 0x3413, 0x0024, 0xf400, 0x4512, 0x0030, 0x0010, 0x0000, 0x0201, 0x2900, + 0x0c80, 0x34f3, 0x0024, 0x3000, 0x0024, 0xb010, 0x0024, 0x0000, 0x0100, + 0x2801, 0xec95, 0x0000, 0x0401, 0x2922, 0x1880, 0x3613, 0x0024, 0x2921, + 0xdd40, 0x3613, 0x0024, 0x2801, 0xeac0, 0xb78e, 0x4006, 0x3000, 0x0024, + 0x4080, 0x0024, 0x0000, 0x0024, 0x2801, 0xec89, 0xf292, 0x0024, 0x6012, + 0x904c, 0x0006, 0x05d1, 0x2801, 0xe318, 0x3100, 0x0024, 0x3000, 0x0024, + 0x4090, 0x0024, 0x3800, 0x0024, 0x3100, 0x0024, 0x4080, 0x4512, 0x34f3, + 0x184c, 0x2801, 0xe5d5, 0x0007, 0x0553, 0x36f3, 0x0800, 0x6090, 0x0024, + 0x4080, 0xa800, 0x0000, 0x0024, 0x2801, 0xec88, 0x0000, 0x0024, 0x3009, + 0x184c, 0x0006, 0xf312, 0x4ffe, 0xb841, 0x2921, 0xdd40, 0x6892, 0x41c7, + 0xb182, 0x9bcc, 0x291a, 0x8a40, 0xcfce, 0x0024, 0x0004, 0x0001, 0xb880, + 0x010c, 0x6890, 0x2000, 0x0007, 0x80d0, 0xb880, 0xa800, 0x3000, 0x2c00, + 0x0007, 0x1ad0, 0xff82, 0x0024, 0x48b2, 0x0024, 0xf400, 0x4040, 0x0000, + 0x03c1, 0xb010, 0x0024, 0x3009, 0x2000, 0x0000, 0x0201, 0x0030, 0x0010, + 0x3000, 0x0024, 0xb010, 0x0024, 0x0000, 0x0180, 0x2801, 0xc1c5, 0x0000, + 0x0024, 0x6890, 0x1bcd, 0x36f3, 0xd80e, 0x36f4, 0x9813, 0x36f4, 0x1811, + 0x36f0, 0xd804, 0x36f0, 0x5802, 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, + 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, 0x0024, 0x3e12, 0xb817, + 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3615, 0x0024, 0x0000, 0x800a, 0x3e10, + 0xb804, 0x3e01, 0x534c, 0xbe8a, 0x10c0, 0x4080, 0x0024, 0x0000, 0x0024, + 0x2801, 0xf6c5, 0x0000, 0x0024, 0x2903, 0xa300, 0x4082, 0x184c, 0x4c8a, + 0x134c, 0x0000, 0x0001, 0x6890, 0x10c2, 0x4294, 0x0024, 0xac22, 0x0024, + 0xbec2, 0x0024, 0x0000, 0x0024, 0x2801, 0xf6c5, 0x0000, 0x0024, 0x6890, + 0x134c, 0xb882, 0x10c2, 0xac22, 0x0024, 0x4c92, 0x0024, 0xdc92, 0x0024, + 0xceca, 0x0024, 0x4e82, 0x1bc5, 0x36f0, 0x9804, 0x3405, 0x9014, 0x36f3, + 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, 0x0024, + 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3645, 0x0024, 0x0000, + 0x800a, 0x3e10, 0x3801, 0x3e10, 0xb803, 0x3e11, 0x3805, 0x3e11, 0xb807, + 0x3e14, 0x104c, 0x2903, 0x9bc0, 0x0000, 0x0081, 0x4080, 0x3040, 0x0000, + 0x0101, 0x2801, 0xfdc5, 0x0000, 0x0024, 0x4090, 0x0024, 0x0006, 0x8050, + 0x2802, 0x11d5, 0x0000, 0x0024, 0x2903, 0x9bc0, 0x3613, 0x0024, 0xb880, + 0x3000, 0x2802, 0x0f80, 0x3009, 0x3380, 0x2903, 0x9bc0, 0x4122, 0x10cc, + 0x3cf0, 0x0024, 0x3001, 0x0024, 0x3400, 0x0024, 0x6800, 0x0024, 0xa408, + 0x9040, 0x4080, 0x0024, 0x0000, 0x07c1, 0x2802, 0x0355, 0x6894, 0x1380, + 0x6894, 0x130c, 0x3460, 0x0024, 0x6408, 0x4481, 0x4102, 0x1380, 0xf400, + 0x4052, 0x0000, 0x07c1, 0x34f0, 0xc024, 0x6234, 0x0024, 0x6824, 0x0024, + 0xa122, 0x0024, 0x6014, 0x0024, 0x0000, 0x0141, 0x2802, 0x0a55, 0x0000, + 0x0024, 0x2903, 0x9bc0, 0x3613, 0x0024, 0x2802, 0x08c0, 0xb88a, 0x4002, + 0x2901, 0xef40, 0x3e00, 0x8024, 0x4c8e, 0xa801, 0x0000, 0x0201, 0x3a10, + 0x1bcc, 0x3000, 0x0024, 0xb010, 0x0024, 0x0000, 0x0024, 0x2802, 0x0e55, + 0x659a, 0x0024, 0x6540, 0x184c, 0x0030, 0x0010, 0x2802, 0x0648, 0x0000, + 0x0024, 0x2802, 0x0e40, 0x36f3, 0x0024, 0x2802, 0x0d00, 0xb88a, 0x0024, + 0x2903, 0x74c0, 0x34d0, 0x4024, 0x4c8f, 0xa0a1, 0x0000, 0x0201, 0x3000, + 0x084c, 0xb010, 0x0024, 0x0000, 0x0024, 0x2802, 0x0e55, 0x659a, 0x0024, + 0x6540, 0x10cc, 0x0030, 0x0010, 0x2802, 0x0ac8, 0x0000, 0x0024, 0x34d3, + 0x0024, 0x3423, 0x0024, 0xf400, 0x4510, 0x3009, 0x1380, 0x6090, 0x0024, + 0x3009, 0x2000, 0x6892, 0x108c, 0x34f0, 0x9000, 0xa122, 0x984c, 0x6016, + 0x13c1, 0x0000, 0x0102, 0x2801, 0xff08, 0x0006, 0x8150, 0x2802, 0x1240, + 0x3009, 0x1bcc, 0x6890, 0x938c, 0x3800, 0x0024, 0x36f4, 0x0024, 0x36f1, + 0x9807, 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f0, 0x1801, 0x3405, 0x9014, + 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, + 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3615, 0x0024, + 0x0000, 0x800a, 0x3e10, 0x3801, 0x3e10, 0xb804, 0x3e11, 0xb807, 0x3e14, + 0x3811, 0x3e04, 0x934c, 0x3430, 0x0024, 0x4080, 0x0024, 0x0000, 0x0206, + 0x2802, 0x1b45, 0x0006, 0x8151, 0x3101, 0x130c, 0xff0c, 0x1102, 0x6408, + 0x0024, 0x4204, 0x0024, 0xb882, 0x4092, 0x1005, 0xfe02, 0x48be, 0x0024, + 0x4264, 0x0024, 0x2903, 0xe080, 0xf400, 0x4090, 0x36f4, 0x8024, 0x36f4, + 0x1811, 0x36f1, 0x9807, 0x36f0, 0x9804, 0x36f0, 0x1801, 0x3405, 0x9014, + 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, + 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3675, 0x0024, + 0x3643, 0x0024, 0x0000, 0x800a, 0x3e10, 0x3801, 0x0000, 0x0181, 0x3e10, + 0xb803, 0x3e11, 0x3806, 0x3e11, 0xf810, 0x3e14, 0x7812, 0x3e13, 0xf80e, + 0x2903, 0x7dc0, 0x3e03, 0x4024, 0x2903, 0x9bc0, 0x4088, 0x184c, 0x3413, + 0x184c, 0x2903, 0x9bc0, 0x6892, 0x3040, 0x4080, 0x3040, 0x0000, 0x0000, + 0x2802, 0x28c5, 0x0000, 0x0024, 0x6890, 0x0024, 0x2903, 0x7dc0, 0x3cd0, + 0x0024, 0x4080, 0x0024, 0x0000, 0x0024, 0x2802, 0x2915, 0x0000, 0x0024, + 0x3433, 0x0024, 0xf400, 0x4510, 0x34d0, 0x0024, 0x6090, 0x0024, 0x2903, + 0x7dc0, 0x3800, 0x0024, 0x4080, 0x10cc, 0xf400, 0x4510, 0x2802, 0x2685, + 0x34d0, 0x0024, 0x2802, 0x2900, 0x0000, 0x0024, 0x3cd0, 0x0024, 0x3433, + 0x0024, 0x34a0, 0x0024, 0xf400, 0x4510, 0x3430, 0x4024, 0x6100, 0x0024, + 0x0000, 0x0341, 0x3840, 0x0024, 0x3000, 0x0024, 0x6012, 0x0024, 0x0006, + 0x0681, 0x2802, 0x4681, 0x4012, 0x0024, 0xf400, 0x4057, 0x3702, 0x0024, + 0x2000, 0x0000, 0x0000, 0x0024, 0x34d3, 0x184c, 0x3430, 0x8024, 0x2901, + 0xef40, 0x3e00, 0x8024, 0x36f3, 0x11cc, 0xb888, 0x104c, 0x3c10, 0x0024, + 0x3c90, 0x4024, 0x2802, 0x3240, 0x34e3, 0x0024, 0x3411, 0x8024, 0x3491, + 0xc024, 0x4f82, 0x128c, 0x3400, 0x4024, 0x4142, 0x0024, 0xf400, 0x4050, + 0x3800, 0x0024, 0x3440, 0x4024, 0x4142, 0x0024, 0x6498, 0x4050, 0x3009, + 0x2007, 0x0006, 0x8150, 0x3000, 0x11cc, 0x6402, 0x104c, 0x0000, 0x0024, + 0x2802, 0x2f88, 0x0000, 0x0024, 0x3493, 0x0024, 0x2802, 0x6240, 0x34f3, + 0x0024, 0x2802, 0x39c0, 0xb888, 0x0024, 0x3430, 0x8024, 0x2901, 0xef40, + 0x3e00, 0x8024, 0x4c8e, 0x130c, 0x3400, 0x5bcc, 0x4142, 0x0024, 0xf400, + 0x4050, 0x3800, 0x0024, 0x3440, 0x4024, 0x4142, 0x0024, 0xf400, 0x4050, + 0x0000, 0x0201, 0x3009, 0x2007, 0x0030, 0x0010, 0x3000, 0x0024, 0xb010, + 0x0024, 0x0000, 0x0024, 0x2802, 0x6255, 0x6498, 0x0024, 0x0006, 0x8150, + 0x3000, 0x134c, 0x6402, 0x984c, 0x0000, 0x0024, 0x2802, 0x3508, 0x0000, + 0x0024, 0x2802, 0x6240, 0x3433, 0x1bcc, 0x0000, 0x0201, 0xb888, 0x104c, + 0x3430, 0x184c, 0x6010, 0x0024, 0x6402, 0x3000, 0x0000, 0x0201, 0x2802, + 0x4258, 0x0030, 0x0010, 0x4090, 0x124c, 0x2402, 0x4140, 0x0000, 0x0024, + 0x3430, 0x8024, 0x2901, 0xef40, 0x3e00, 0x8024, 0x4c8e, 0x130c, 0x3400, + 0x4024, 0x4142, 0x0024, 0xf400, 0x4050, 0x3800, 0x0024, 0x3410, 0x4024, + 0x4142, 0x0024, 0x6498, 0x4050, 0x3009, 0x2007, 0x0030, 0x0010, 0x0000, + 0x0201, 0x3473, 0x0024, 0x3490, 0x0024, 0x3e00, 0x13cc, 0x2901, 0xf880, + 0x3444, 0x8024, 0x3000, 0x1bcc, 0xb010, 0x0024, 0x0000, 0x0024, 0x2802, + 0x6255, 0x0000, 0x0024, 0x34c3, 0x184c, 0x3470, 0x0024, 0x3e10, 0x104c, + 0x34c0, 0x4024, 0x2902, 0x14c0, 0x3e00, 0x4024, 0x2802, 0x6240, 0x36e3, + 0x0024, 0x0000, 0x0801, 0x3413, 0x0024, 0x34f0, 0x0024, 0x6012, 0x0024, + 0x0000, 0x07c1, 0x2802, 0x6188, 0x0000, 0x0024, 0x6010, 0x114c, 0xb888, + 0x32c0, 0x6402, 0x0024, 0x0000, 0x0101, 0x2802, 0x4e18, 0x0000, 0x0024, + 0x4090, 0x134c, 0x2402, 0x4d40, 0x3009, 0x184c, 0x3430, 0x8024, 0x2901, + 0xef40, 0x3e00, 0x8024, 0x4c8e, 0x130c, 0x3400, 0x4024, 0x4142, 0x0024, + 0xf400, 0x4050, 0x3800, 0x0024, 0x3410, 0x4024, 0x4142, 0x0024, 0x6498, + 0x4050, 0x3009, 0x2007, 0x0000, 0x0101, 0x3433, 0x1bcc, 0x2903, 0x9bc0, + 0x3613, 0x0024, 0x0000, 0x0141, 0x6090, 0x118c, 0x2903, 0x9bc0, 0x3ca0, + 0x184c, 0x3473, 0x184c, 0xb888, 0x3380, 0x3400, 0x0024, 0x6402, 0x0024, + 0x0000, 0x0201, 0x2802, 0x54d8, 0x0000, 0x0024, 0x4090, 0x104c, 0x2402, + 0x5400, 0x0000, 0x0024, 0x34a0, 0x8024, 0x2901, 0xef40, 0x3e00, 0x8024, + 0x0006, 0x8002, 0x4244, 0x118c, 0x4244, 0x0024, 0x6498, 0x4095, 0x3009, + 0x3440, 0x3009, 0x37c1, 0x0000, 0x0201, 0x34f3, 0x0024, 0x0030, 0x0010, + 0x3490, 0x0024, 0x3e00, 0x138c, 0x2901, 0xf880, 0x3444, 0x8024, 0x3000, + 0x1bcc, 0xb010, 0x0024, 0x0000, 0x0024, 0x2802, 0x6255, 0x4112, 0x0024, + 0x3463, 0x0024, 0x34a0, 0x0024, 0x6012, 0x0024, 0x0006, 0x8111, 0x2802, + 0x5e19, 0x0000, 0x0024, 0x3100, 0x11cc, 0x3490, 0x4024, 0x4010, 0x0024, + 0x0000, 0x0a01, 0x6012, 0x0024, 0x0006, 0x8151, 0x2802, 0x5e18, 0x0000, + 0x0024, 0x3613, 0x114c, 0x3101, 0x3804, 0x3490, 0x8024, 0x6428, 0x138c, + 0x3470, 0x8024, 0x3423, 0x0024, 0x3420, 0xc024, 0x4234, 0x1241, 0x4380, + 0x4092, 0x2903, 0xe080, 0x0006, 0x8010, 0x2802, 0x6240, 0x3009, 0x1bcc, + 0x0006, 0x8151, 0x3613, 0x114c, 0x3101, 0x3804, 0x3490, 0x8024, 0x6428, + 0x138c, 0x3470, 0x8024, 0x3423, 0x0024, 0x3420, 0xc024, 0x4234, 0x1241, + 0x4380, 0x4092, 0x2903, 0xea40, 0x0006, 0x8010, 0x2802, 0x6240, 0x3009, + 0x1bcc, 0x0006, 0x8050, 0x6890, 0x0024, 0x3800, 0x0024, 0x3433, 0x0024, + 0x34d0, 0x0024, 0x4080, 0x0024, 0x0006, 0x8150, 0x2802, 0x67c5, 0x0000, + 0x0024, 0x3000, 0x11cc, 0xb888, 0x10cc, 0x6402, 0x3240, 0x3493, 0x0024, + 0x3444, 0x8024, 0x2802, 0x67d8, 0x4090, 0x0024, 0x2402, 0x6780, 0x0000, + 0x0024, 0x6499, 0x2620, 0xb78e, 0x4001, 0x0000, 0x0000, 0x3433, 0x0024, + 0xcfce, 0x1340, 0xaf0e, 0x0024, 0x3a11, 0xa807, 0x36f3, 0x4024, 0x36f3, + 0xd80e, 0x36f4, 0x5812, 0x36f1, 0xd810, 0x36f1, 0x1806, 0x36f0, 0x9803, + 0x36f0, 0x1801, 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, + 0x0000, 0x36f2, 0x9817, 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, + 0x3e05, 0xb814, 0x3615, 0x0024, 0x0000, 0x800a, 0x3e10, 0x7802, 0x3e10, + 0xf804, 0x0000, 0x3fc3, 0x3e11, 0x7806, 0x3e11, 0xf810, 0xbc82, 0x12cc, + 0x3404, 0x0024, 0x3023, 0x0024, 0x3810, 0x0024, 0x38f0, 0x4024, 0x3454, + 0x0024, 0x3810, 0x0024, 0x38f0, 0x4024, 0x2903, 0x9bc0, 0x0000, 0x0201, + 0x0006, 0x9301, 0x4088, 0x134c, 0x3400, 0x8024, 0xd204, 0x0024, 0xb234, + 0x0024, 0x4122, 0x0024, 0xf400, 0x4055, 0x3500, 0x0024, 0x3c30, 0x0024, + 0x0000, 0x2000, 0xb400, 0x0024, 0x0000, 0x3001, 0x2802, 0x7555, 0x0000, + 0x3800, 0x0000, 0x0041, 0xfe42, 0x12cc, 0x48b2, 0x1090, 0x3810, 0x0024, + 0x38f0, 0x4024, 0x2802, 0x9640, 0x3430, 0x0024, 0xb400, 0x0024, 0x6012, + 0x0024, 0x0000, 0x3801, 0x2802, 0x7895, 0x0000, 0x3c00, 0x0000, 0x07c0, + 0x0000, 0x0041, 0xb400, 0x12cc, 0xfe02, 0x1150, 0x48b2, 0x0024, 0x689a, + 0x2040, 0x2802, 0x9500, 0x38f0, 0x4024, 0xb400, 0x0024, 0x6012, 0x0024, + 0x0000, 0x3c01, 0x2802, 0x7c15, 0x0000, 0x3e00, 0x0000, 0x03c0, 0x0000, + 0x0085, 0x4592, 0x12cc, 0xb400, 0x1150, 0xfe02, 0x0024, 0x48b2, 0x0024, + 0x3810, 0x0024, 0x2802, 0x9500, 0x38f0, 0x4024, 0xb400, 0x0024, 0x6012, + 0x0024, 0x0000, 0x3e01, 0x2802, 0x7f95, 0x0000, 0x3f00, 0x0000, 0x01c0, + 0xf20a, 0x12cc, 0xb400, 0x1150, 0xf252, 0x0024, 0xfe02, 0x0024, 0x48b2, + 0x0024, 0x3810, 0x0024, 0x2802, 0x9500, 0x38f0, 0x4024, 0xb400, 0x130c, + 0x6012, 0x0024, 0x0000, 0x3f01, 0x2802, 0x8315, 0x4390, 0x0024, 0x0000, + 0x0041, 0x0000, 0x0105, 0x4590, 0x13cc, 0xb400, 0x1150, 0xfe02, 0x0024, + 0x48b2, 0x0024, 0x3810, 0x0024, 0x2802, 0x9500, 0x38f0, 0x4024, 0xb400, + 0x0024, 0x6012, 0x1100, 0x0000, 0x01c1, 0x2802, 0x8695, 0x0000, 0x0024, + 0x0000, 0x0041, 0x0000, 0x0145, 0x6890, 0x12cc, 0xb400, 0x1150, 0xfe02, + 0x0024, 0x48b2, 0x0024, 0x3810, 0x0024, 0x2802, 0x9500, 0x38f0, 0x4024, + 0x6012, 0x0024, 0x0000, 0x3f81, 0x2802, 0x8915, 0xb430, 0x0024, 0x6012, + 0x0024, 0x0000, 0x0024, 0x2802, 0x8915, 0x0000, 0x0024, 0x2802, 0x9500, + 0x0000, 0x0185, 0x2802, 0x9640, 0xc890, 0x0024, 0x0000, 0x3fc3, 0x0000, + 0x0201, 0x34d3, 0x0024, 0x2903, 0x9bc0, 0x3433, 0x184c, 0x0006, 0x9301, + 0x4088, 0x134c, 0x3400, 0x8024, 0xd204, 0x0024, 0xb234, 0x0024, 0x4122, + 0x0024, 0xf400, 0x4055, 0x0000, 0x2001, 0x3500, 0x0024, 0x3c30, 0x0024, + 0x0000, 0x3000, 0xb400, 0x0024, 0x6012, 0x0024, 0x0000, 0x0182, 0x2802, + 0x8f45, 0x0000, 0x0024, 0x2802, 0x9640, 0xc890, 0x0024, 0x459a, 0x12cc, + 0x3404, 0x0024, 0x3023, 0x0024, 0x3010, 0x0024, 0x30d0, 0x4024, 0xac22, + 0x0046, 0x003f, 0xf982, 0x3011, 0xc024, 0x0000, 0x0023, 0xaf2e, 0x0024, + 0x0000, 0x0182, 0xccf2, 0x0024, 0x0000, 0x0fc6, 0x0000, 0x0047, 0xb46c, + 0x2040, 0xfe6e, 0x23c1, 0x3454, 0x0024, 0x3010, 0x0024, 0x30f0, 0x4024, + 0xac22, 0x0024, 0xccb2, 0x0024, 0x3810, 0x0024, 0x38f0, 0x4024, 0x458a, + 0x134c, 0x0000, 0x0201, 0x2802, 0x8a55, 0x0000, 0x3fc3, 0x3430, 0x0024, + 0x36f1, 0xd810, 0x36f1, 0x5806, 0x36f0, 0xd804, 0x36f0, 0x5802, 0x3405, + 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, + 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3675, + 0x0024, 0x3633, 0x0024, 0x0000, 0x800a, 0x3e10, 0x3801, 0x3e10, 0xb803, + 0x3e11, 0x3805, 0x3e11, 0xb807, 0x3e14, 0x3811, 0x3e14, 0xb813, 0x3e13, + 0xf80e, 0x3e03, 0x4024, 0x2903, 0xc780, 0x0000, 0x0381, 0x000f, 0xff81, + 0x6012, 0x0024, 0x0000, 0x0401, 0x2802, 0x9f05, 0x0000, 0x0024, 0x0000, + 0x0201, 0x3613, 0x0024, 0x2903, 0x9bc0, 0x0003, 0x5508, 0x003f, 0xfe04, + 0x0006, 0x8090, 0xb880, 0x11cc, 0x3413, 0x184c, 0x3c90, 0x0024, 0x2903, + 0x9bc0, 0x34f3, 0x0024, 0x0006, 0x9301, 0x3473, 0x184c, 0x3c10, 0x0024, + 0x34f0, 0x8024, 0x3400, 0xc024, 0xa346, 0x0024, 0xd234, 0x0024, 0x0000, + 0x3fc3, 0xb234, 0x0024, 0x4122, 0x1042, 0xf400, 0x4055, 0x0006, 0x9301, + 0x3500, 0x0024, 0xd024, 0x3000, 0xb234, 0x0024, 0x4122, 0x0024, 0x6892, + 0x4055, 0x3500, 0x0024, 0x3cf0, 0x0024, 0x34a0, 0x0024, 0xf100, 0x0024, + 0xb010, 0x0024, 0x3c60, 0x0024, 0x34b0, 0x0024, 0xb010, 0x0024, 0x0000, + 0x0201, 0x2903, 0x9bc0, 0x3ce0, 0x0024, 0x0006, 0x9301, 0x3473, 0x184c, + 0x3c10, 0x0024, 0x34f0, 0x8024, 0x3410, 0xc024, 0xd234, 0x0024, 0x0000, + 0x3fc3, 0xb234, 0x0024, 0x4122, 0x0024, 0xf400, 0x4055, 0x003f, 0xff01, + 0x3500, 0x0024, 0x3cf0, 0x0024, 0x34c0, 0x0024, 0xa010, 0x0024, 0x0000, + 0x03c1, 0x3c40, 0x0024, 0x34d0, 0x0024, 0xb010, 0x0024, 0x0000, 0x0201, + 0x2903, 0x9bc0, 0x3cc0, 0x0024, 0x0006, 0x9301, 0x3473, 0x0024, 0x3c10, + 0x0024, 0x34f0, 0x8024, 0x3410, 0xc024, 0xd234, 0x0024, 0x0000, 0x3fc3, + 0xb234, 0x0024, 0x4122, 0x0024, 0xf400, 0x4055, 0x003f, 0xff01, 0x3500, + 0x0024, 0x3cf0, 0x0024, 0x3400, 0x0024, 0xa010, 0x0024, 0x0000, 0x01c1, + 0x3800, 0x0024, 0x34e0, 0x0024, 0xf100, 0x0024, 0xb010, 0x0024, 0x6892, + 0x3080, 0x34f0, 0x0024, 0xb010, 0x0024, 0x3cb0, 0x0024, 0x3450, 0x0024, + 0x34a0, 0x4024, 0xc010, 0x0024, 0x0000, 0x0181, 0x2802, 0xb585, 0x3000, + 0x0024, 0x6890, 0x03cc, 0x2803, 0x5500, 0x3800, 0x0024, 0x6012, 0x0024, + 0x0000, 0x0201, 0x2802, 0xb718, 0x0000, 0x0024, 0x2802, 0xba00, 0x6090, + 0x004c, 0x6012, 0x0024, 0x0000, 0x0281, 0x2802, 0xb948, 0x6012, 0x0024, + 0x0000, 0x0080, 0x2802, 0xb959, 0x0000, 0x0024, 0x2802, 0xba00, 0x3013, + 0x0024, 0x6890, 0x03cc, 0x2803, 0x5500, 0x3800, 0x0024, 0x0000, 0x0201, + 0x3800, 0x114c, 0x34b0, 0x0024, 0x6012, 0x0024, 0x0006, 0x09c1, 0x2802, + 0xc441, 0x4012, 0x0024, 0xf400, 0x4057, 0x3702, 0x0024, 0x2000, 0x0000, + 0x0000, 0x0024, 0x2802, 0xc440, 0x0000, 0x0024, 0x0000, 0x0200, 0x0006, + 0x8110, 0x2802, 0xc440, 0x3800, 0x0024, 0x0000, 0x0300, 0x0006, 0x8110, + 0x2802, 0xc440, 0x3800, 0x0024, 0x0006, 0x8050, 0x6890, 0x0024, 0x2803, + 0x5500, 0x3800, 0x0024, 0x0000, 0x0400, 0x0006, 0x8110, 0x2802, 0xc440, + 0x3800, 0x0024, 0x0000, 0x0500, 0x0006, 0x8110, 0x2802, 0xc440, 0x3800, + 0x0024, 0x0000, 0x0600, 0x0006, 0x8110, 0x2802, 0xc440, 0x3800, 0x0024, + 0x0006, 0x8050, 0x6890, 0x0024, 0x2803, 0x5500, 0x3800, 0x0024, 0x3423, + 0x184c, 0x3460, 0x0024, 0x4080, 0x0024, 0x0006, 0x8200, 0x2802, 0xc985, + 0x3e10, 0x0024, 0x0000, 0x01c0, 0x3e10, 0x0024, 0x3490, 0x0024, 0x2902, + 0x6ac0, 0x3e00, 0x13cc, 0x36d3, 0x11cc, 0x3413, 0x0024, 0x4080, 0x3240, + 0x34f3, 0x0024, 0x2802, 0xcd58, 0x0000, 0x0024, 0x0006, 0x8010, 0x6890, + 0x0024, 0x2803, 0x5500, 0x3800, 0x0024, 0x0000, 0x0180, 0x3e10, 0x0024, + 0x3490, 0x0024, 0x2902, 0x6ac0, 0x3e00, 0x13cc, 0x36d3, 0x11cc, 0x3413, + 0x0024, 0x4080, 0x3240, 0x34f3, 0x0024, 0x2802, 0xcd58, 0x0000, 0x0024, + 0x0006, 0x8010, 0x6890, 0x0024, 0x2803, 0x5500, 0x3800, 0x0024, 0x0000, + 0x0201, 0x3433, 0x0024, 0x34d0, 0x0024, 0x6012, 0x0024, 0x0006, 0x0bc1, + 0x2802, 0xdf41, 0x4012, 0x0024, 0xf400, 0x4057, 0x3702, 0x0024, 0x2000, + 0x0000, 0x0000, 0x0024, 0x0006, 0x8050, 0x6890, 0x0024, 0x2803, 0x5500, + 0x3800, 0x0024, 0x0000, 0x3000, 0x2802, 0xe100, 0x0006, 0x8150, 0x0000, + 0x9000, 0x0006, 0x8150, 0x3433, 0x0024, 0x34d0, 0x4024, 0x4192, 0x0024, + 0x4192, 0x0024, 0x2802, 0xe100, 0xa010, 0x0024, 0x0000, 0x0201, 0x0006, + 0x8150, 0x2903, 0x9bc0, 0x3613, 0x0024, 0x0006, 0x9301, 0x3473, 0x0024, + 0x3c10, 0x0024, 0x34f0, 0x8024, 0x3410, 0xc024, 0xd234, 0x0024, 0x0000, + 0x3fc3, 0xb234, 0x0024, 0x4122, 0x0024, 0xf400, 0x4055, 0x3500, 0x0024, + 0x3cf0, 0x0024, 0x3490, 0x0024, 0x2802, 0xe100, 0x6090, 0x0024, 0x003f, + 0xfe04, 0x0000, 0x0401, 0x0006, 0x8150, 0x2903, 0x9bc0, 0x3613, 0x0024, + 0x0006, 0x9301, 0x3473, 0x0024, 0x3c10, 0x0024, 0x34f0, 0x8024, 0x3400, + 0xc024, 0xa346, 0x0024, 0xd234, 0x0024, 0x0000, 0x3fc3, 0xb234, 0x0024, + 0x4122, 0x1042, 0xf400, 0x4055, 0x0006, 0x9301, 0x3500, 0x0024, 0xd024, + 0x3000, 0xb234, 0x0024, 0x4122, 0x0024, 0xf400, 0x4055, 0x3500, 0x0024, + 0x3cf0, 0x0024, 0x3490, 0x0024, 0x2802, 0xe100, 0x6090, 0x0024, 0x0000, + 0x4000, 0x0000, 0x0202, 0x0006, 0x8150, 0x3433, 0x0024, 0x34d0, 0x4024, + 0x6122, 0x0024, 0xa010, 0x0024, 0x0004, 0x8001, 0x3800, 0x110c, 0x0006, + 0x8150, 0x3000, 0x0024, 0x6012, 0x1300, 0x0000, 0x0401, 0x2802, 0xe3c9, + 0x0000, 0x0024, 0x6890, 0x82cc, 0x2803, 0x5500, 0x3800, 0x0024, 0x6012, + 0x0024, 0x0006, 0x0dc1, 0x2803, 0x0b41, 0x4012, 0x0024, 0xf400, 0x4057, + 0x3702, 0x0024, 0x2000, 0x0000, 0x0000, 0x0024, 0x2803, 0x0b40, 0x0000, + 0x0024, 0x0016, 0x2200, 0x0006, 0x8190, 0x6892, 0x2040, 0x2803, 0x0b40, + 0x38f0, 0x4024, 0x002c, 0x4400, 0x0000, 0x0081, 0x0006, 0x8190, 0x3810, + 0x0024, 0x2803, 0x0b40, 0x38f0, 0x4024, 0x003b, 0x8000, 0x0000, 0x0081, + 0x0006, 0x8190, 0x3810, 0x0024, 0x2803, 0x0b40, 0x38f0, 0x4024, 0x0007, + 0xd000, 0x0006, 0x8190, 0xb882, 0x2040, 0x2803, 0x0b40, 0x38f0, 0x4024, + 0x000f, 0xa000, 0x0006, 0x8190, 0xb882, 0x2040, 0x2803, 0x0b40, 0x38f0, + 0x4024, 0x0015, 0x8880, 0x0006, 0x8190, 0xb882, 0x2040, 0x2803, 0x0b40, + 0x38f0, 0x4024, 0x0017, 0x7000, 0x0006, 0x8190, 0xb882, 0x2040, 0x2803, + 0x0b40, 0x38f0, 0x4024, 0x001f, 0x4000, 0x0006, 0x8190, 0xb882, 0x2040, + 0x2803, 0x0b40, 0x38f0, 0x4024, 0x002b, 0x1100, 0x0006, 0x8190, 0xb882, + 0x2040, 0x2803, 0x0b40, 0x38f0, 0x4024, 0x002e, 0xe000, 0x0006, 0x8190, + 0xb882, 0x2040, 0x2803, 0x0b40, 0x38f0, 0x4024, 0x001d, 0xc000, 0x0006, + 0x8190, 0x6892, 0x2040, 0x2803, 0x0b40, 0x38f0, 0x4024, 0x0006, 0x8190, + 0x0000, 0x0201, 0x0000, 0xfa04, 0x2903, 0x9bc0, 0x3613, 0x0024, 0x0006, + 0x9301, 0xb88a, 0x11cc, 0x3c10, 0x0024, 0x34f0, 0x8024, 0x3410, 0xc024, + 0xd234, 0x0024, 0x0000, 0x3fc3, 0xb234, 0x0024, 0x4122, 0x0024, 0xf400, + 0x4055, 0x3500, 0x0024, 0x3cf0, 0x0024, 0x3490, 0x0024, 0xfe50, 0x4005, + 0x48b2, 0x0024, 0xfeca, 0x0024, 0x40b2, 0x0024, 0x3810, 0x0024, 0x2803, + 0x0b40, 0x38f0, 0x4024, 0x003f, 0xfe04, 0x0000, 0x0401, 0x0006, 0x8190, + 0x2903, 0x9bc0, 0x3613, 0x0024, 0x0006, 0x9301, 0x3473, 0x0024, 0x3c10, + 0x0024, 0x34f0, 0x8024, 0x3400, 0xc024, 0xa346, 0x0024, 0xd234, 0x0024, + 0x0000, 0x3fc3, 0xb234, 0x0024, 0x4122, 0x1042, 0xf400, 0x4055, 0x0006, + 0x9301, 0x3500, 0x0024, 0xd024, 0x3000, 0xb234, 0x0024, 0x4122, 0x0024, + 0xf400, 0x4055, 0x0000, 0x0041, 0x3500, 0x0024, 0x3cf0, 0x0024, 0x3490, + 0x0024, 0xfe02, 0x0024, 0x48b2, 0x0024, 0x3810, 0x0024, 0x2803, 0x0b40, + 0x38f0, 0x4024, 0x003f, 0xfe04, 0x0000, 0x0401, 0x0006, 0x8190, 0x2903, + 0x9bc0, 0x3613, 0x0024, 0x0006, 0x9301, 0x3473, 0x0024, 0x3c10, 0x0024, + 0x34f0, 0x8024, 0x3400, 0xc024, 0xa346, 0x0024, 0xd234, 0x0024, 0x0000, + 0x3fc3, 0xb234, 0x0024, 0x4122, 0x1042, 0xf400, 0x4055, 0x0006, 0x9301, + 0x3500, 0x0024, 0xd024, 0x3000, 0xb234, 0x0024, 0x4122, 0x0024, 0xf400, + 0x4055, 0x3500, 0x0024, 0x3cf0, 0x0024, 0x0000, 0x0280, 0x3490, 0x4024, + 0xfe02, 0x0024, 0x48b2, 0x0024, 0x3810, 0x0024, 0x2803, 0x0b40, 0x38f0, + 0x4024, 0x0006, 0x8010, 0x6890, 0x0024, 0x2803, 0x5500, 0x3800, 0x0024, + 0x0000, 0x0201, 0x2903, 0x9bc0, 0x3613, 0x11cc, 0x3c10, 0x0024, 0x3490, + 0x4024, 0x6014, 0x13cc, 0x0000, 0x0081, 0x2803, 0x0e85, 0x0006, 0x80d0, + 0x0006, 0x8010, 0x6890, 0x0024, 0x2803, 0x5500, 0x3800, 0x0024, 0x3000, + 0x0024, 0x6012, 0x0024, 0x0000, 0x0241, 0x2803, 0x1309, 0x0000, 0x0024, + 0x6890, 0x034c, 0xb882, 0x2000, 0x0006, 0x8310, 0x2914, 0xbec0, 0x0000, + 0x1000, 0x0000, 0x0800, 0x3613, 0x0024, 0x3e10, 0x0024, 0x0006, 0x8300, + 0x290c, 0x7300, 0x3e10, 0x0024, 0x2803, 0x5500, 0x36e3, 0x0024, 0x0006, + 0x8110, 0x30e1, 0x184c, 0x3000, 0x0024, 0x6012, 0x0024, 0x0008, 0x0001, + 0x2803, 0x1515, 0x0000, 0x0024, 0x6498, 0x0024, 0x3e10, 0x4024, 0x0000, + 0x0081, 0x2902, 0x1dc0, 0x3e01, 0x0024, 0x36e3, 0x004c, 0x3000, 0x0024, + 0x6012, 0x0024, 0x000b, 0x8011, 0x2803, 0x20d5, 0x0006, 0x8112, 0x0000, + 0x0201, 0x0004, 0x0010, 0x2915, 0x8300, 0x0001, 0x0000, 0x000b, 0x8011, + 0x0005, 0x0010, 0x291f, 0xc6c0, 0x0001, 0x0000, 0x0006, 0x8110, 0x30e1, + 0x0024, 0x3000, 0x0024, 0x6012, 0x0024, 0x0000, 0x0281, 0x2803, 0x1c45, + 0x6012, 0x0024, 0x000b, 0x8001, 0x2803, 0x1cd5, 0x3613, 0x0024, 0x36f3, + 0x0024, 0x000b, 0x8001, 0x6498, 0x184c, 0x0006, 0x8112, 0x0003, 0x8000, + 0x3e10, 0x4024, 0x2902, 0x1dc0, 0x3e01, 0x0024, 0x36f3, 0x0024, 0x3009, + 0x3844, 0x3e10, 0x0024, 0x0000, 0x0400, 0x3000, 0x8024, 0x0008, 0x0010, + 0x3e00, 0x8024, 0x3201, 0x0024, 0x6408, 0x4051, 0x2903, 0x8740, 0x0003, + 0x2388, 0x0000, 0x0400, 0x0000, 0x0011, 0x3613, 0x008c, 0x30d0, 0x7844, + 0x3e10, 0x4024, 0x3000, 0x8024, 0x0008, 0x0010, 0x3e00, 0x8024, 0x3201, + 0x0024, 0x2903, 0x8740, 0x6408, 0x0024, 0x0006, 0x8a10, 0x0000, 0x01c1, + 0x36e3, 0x0000, 0xb010, 0x9bc4, 0x0000, 0x0024, 0x2803, 0x2785, 0x0000, + 0x0024, 0x6192, 0x184c, 0x2903, 0x9bc0, 0x6102, 0x0024, 0x4088, 0x0024, + 0x0000, 0x0024, 0x2803, 0x2785, 0x0000, 0x0024, 0x6890, 0x0b4c, 0x3a00, + 0x0024, 0x0000, 0x0401, 0x2903, 0x9bc0, 0x3613, 0x11cc, 0x3413, 0x0024, + 0x3c90, 0x0024, 0x290b, 0x1400, 0x34f3, 0x0024, 0x4080, 0x0024, 0x0000, + 0x0024, 0x2803, 0x5195, 0x0000, 0x0024, 0x3423, 0x0024, 0x34e0, 0x0024, + 0x4080, 0x0024, 0x0006, 0x8151, 0x2803, 0x2f05, 0x0000, 0x3200, 0x0000, + 0x0142, 0x0006, 0x8211, 0x3613, 0x0024, 0x3e00, 0x7800, 0x3111, 0x8024, + 0x31d1, 0xc024, 0xfef4, 0x4087, 0x48b6, 0x0440, 0xfeee, 0x07c1, 0x2914, + 0xa580, 0x42b6, 0x0024, 0x2803, 0x3300, 0x0007, 0x89d0, 0x0000, 0x0142, + 0x3613, 0x0024, 0x3e00, 0x7800, 0x3131, 0x8024, 0x3110, 0x0024, 0x31d0, + 0x4024, 0xfe9c, 0x4181, 0x48be, 0x0024, 0xfe82, 0x0440, 0x46be, 0x07c1, + 0xfef4, 0x4087, 0x48b6, 0x0024, 0xfeee, 0x0024, 0x2914, 0xa580, 0x42b6, + 0x0024, 0x0007, 0x89d0, 0x0006, 0x8191, 0x4c8a, 0x9800, 0xfed0, 0x4005, + 0x48b2, 0x0024, 0xfeca, 0x0024, 0x40b2, 0x0024, 0x3810, 0x0024, 0x38f0, + 0x4024, 0x3111, 0x8024, 0x468a, 0x0707, 0x2908, 0xbe80, 0x3101, 0x0024, + 0x3123, 0x11cc, 0x3100, 0x108c, 0x3009, 0x3000, 0x0004, 0x8000, 0x3009, + 0x1241, 0x6014, 0x138c, 0x000b, 0x8011, 0x2803, 0x3941, 0x0000, 0x0024, + 0x3473, 0x0024, 0x3423, 0x0024, 0x3009, 0x3240, 0x34e3, 0x0024, 0x2803, + 0x4fc0, 0x0008, 0x0012, 0x0006, 0x80d0, 0x2803, 0x3ac9, 0x0000, 0x0024, + 0xf400, 0x4004, 0x3000, 0x0024, 0x4090, 0x0024, 0xf400, 0x4480, 0x2803, + 0x4095, 0x000b, 0x8001, 0x0000, 0x0005, 0x6540, 0x0024, 0x0000, 0x0024, + 0x2803, 0x4bd8, 0x4490, 0x0024, 0x2403, 0x3fc0, 0x0000, 0x0024, 0x0006, + 0x8301, 0x4554, 0x0800, 0x4122, 0x0024, 0x659a, 0x4055, 0x0006, 0x8341, + 0x4122, 0x3400, 0xf400, 0x4055, 0x3210, 0x0024, 0x3d00, 0x0024, 0x2803, + 0x4bc0, 0x0000, 0x0024, 0x6014, 0x0024, 0x0001, 0x0000, 0x2803, 0x4815, + 0x0000, 0x0005, 0x0008, 0x0012, 0x0008, 0x0010, 0x0003, 0x8001, 0x0006, + 0x8153, 0x3613, 0x0024, 0x3009, 0x3811, 0x2903, 0xfc00, 0x0004, 0x0011, + 0x0008, 0x0010, 0x0001, 0x0000, 0x291f, 0xc6c0, 0x0005, 0x0011, 0x000f, + 0x0011, 0x0008, 0x0010, 0x33d0, 0x184c, 0x6010, 0xb844, 0x3e10, 0x0024, + 0x0000, 0x0400, 0x3320, 0x4024, 0x3e00, 0x4024, 0x3301, 0x0024, 0x2903, + 0x8740, 0x6408, 0x0024, 0x36e3, 0x0024, 0x3009, 0x1bc4, 0x3009, 0x1bd1, + 0x6540, 0x0024, 0x0000, 0x0024, 0x2803, 0x4bd8, 0x4490, 0x0024, 0x2403, + 0x4b80, 0x0000, 0x0024, 0x0006, 0x8301, 0x4554, 0x0840, 0x4122, 0x0024, + 0x659a, 0x4055, 0x0006, 0x8341, 0x4122, 0x3400, 0xf400, 0x4055, 0x3110, + 0x0024, 0x3d00, 0x0024, 0xf400, 0x4510, 0x0030, 0x0013, 0x3073, 0x184c, + 0x3e11, 0x008c, 0x3009, 0x0001, 0x6140, 0x0024, 0x0000, 0x0201, 0x3009, + 0x2000, 0x0006, 0x8300, 0x290c, 0x7300, 0x3e10, 0x0024, 0x3300, 0x1b8c, + 0xb010, 0x0024, 0x0000, 0x0024, 0x2803, 0x5195, 0x0000, 0x0024, 0x3473, + 0x0024, 0x3423, 0x0024, 0x3009, 0x1240, 0x4080, 0x138c, 0x0000, 0x0804, + 0x2803, 0x39d5, 0x6402, 0x0024, 0x0006, 0xd312, 0x0006, 0xd310, 0x0006, + 0x8191, 0x3010, 0x984c, 0x30f0, 0xc024, 0x0000, 0x0021, 0xf2d6, 0x07c6, + 0x290a, 0xf5c0, 0x4682, 0x0400, 0x6894, 0x0840, 0xb886, 0x0bc1, 0xbcd6, + 0x0024, 0x3a10, 0x8024, 0x3af0, 0xc024, 0x36f3, 0x4024, 0x36f3, 0xd80e, + 0x36f4, 0x9813, 0x36f4, 0x1811, 0x36f1, 0x9807, 0x36f1, 0x1805, 0x36f0, + 0x9803, 0x36f0, 0x1801, 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, + 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, + 0x3815, 0x3e05, 0xb814, 0x3615, 0x0024, 0x0000, 0x800a, 0x3e10, 0x3801, + 0x0020, 0x0001, 0x3e14, 0x3811, 0x0030, 0x0050, 0x0030, 0x0251, 0x3e04, + 0xb813, 0x3000, 0x0024, 0xc012, 0x0024, 0x0019, 0x9300, 0x3800, 0x4024, + 0x2903, 0xae40, 0x3900, 0x0024, 0x2903, 0xbb80, 0x0000, 0x0300, 0xb882, + 0x0024, 0x2914, 0xbec0, 0x0006, 0x8010, 0x0000, 0x1540, 0x0007, 0x8190, + 0x2900, 0xadc0, 0x3800, 0x0024, 0x4080, 0x0024, 0x0000, 0x0024, 0x2803, + 0x6555, 0x0000, 0x0024, 0x0006, 0x8012, 0x3200, 0x0024, 0x4080, 0x0024, + 0x0030, 0x0010, 0x2803, 0x6555, 0x0000, 0x0201, 0x3000, 0x0024, 0xb010, + 0x0024, 0x0000, 0x0024, 0x2803, 0x6555, 0x0000, 0x0024, 0x2900, 0xadc0, + 0x0000, 0x0024, 0x4080, 0x0024, 0x0006, 0x8010, 0x2803, 0x6555, 0x3000, + 0x0024, 0x4080, 0x0024, 0x0000, 0x0201, 0x2803, 0x6185, 0x0030, 0x0010, + 0x0030, 0x0050, 0xf292, 0x0000, 0xb012, 0x0024, 0x3800, 0x4024, 0x0030, + 0x0010, 0x0000, 0x0201, 0x3000, 0x0024, 0xb010, 0x0024, 0x0000, 0x0024, + 0x2900, 0xbe95, 0x0003, 0x6f08, 0x0006, 0x8011, 0x3100, 0x0024, 0x4080, + 0x0024, 0x0000, 0x0024, 0x2803, 0x6d45, 0x0000, 0x0024, 0x0007, 0x8a52, + 0x3200, 0x0024, 0x4080, 0x0024, 0x0000, 0x0024, 0x2803, 0x6d49, 0x0000, + 0x0024, 0xf292, 0x0800, 0x6012, 0x0024, 0x0000, 0x0000, 0x2803, 0x6d05, + 0x0000, 0x0024, 0x3200, 0x0024, 0x4090, 0x0024, 0xb880, 0x2800, 0x3900, + 0x0024, 0x3100, 0x0024, 0x4080, 0x0024, 0x0000, 0x0024, 0x2902, 0x9885, + 0x0003, 0x6648, 0x2900, 0xbe80, 0x0000, 0x0024, 0x0000, 0x0010, 0x0006, + 0x9f51, 0x0006, 0x9f92, 0x0030, 0x0493, 0x0000, 0x0201, 0x6890, 0xa410, + 0x3b00, 0x2810, 0x0006, 0x8a10, 0x3009, 0x0000, 0x6012, 0x0024, 0x0006, + 0x9fd0, 0x2803, 0x7288, 0xb880, 0x0024, 0x6890, 0x0024, 0x3009, 0x2000, + 0x36f4, 0x9813, 0x36f4, 0x1811, 0x36f0, 0x1801, 0x3405, 0x9014, 0x36f3, + 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, 0x0024, + 0x3e10, 0xb810, 0x3e11, 0x3805, 0x3e02, 0x0024, 0x0030, 0x0010, 0xce9a, + 0x0002, 0x0000, 0x0200, 0x2903, 0x7dc0, 0xb024, 0x0024, 0xc020, 0x0024, + 0x0000, 0x0200, 0x2803, 0x7685, 0x6e9a, 0x0002, 0x4182, 0x0024, 0x0000, + 0x0400, 0x2803, 0x7c45, 0xae1a, 0x0024, 0x6104, 0x984c, 0x0000, 0x0024, + 0x2903, 0x9bc9, 0x0003, 0x7c08, 0x6103, 0xe4e5, 0x2903, 0x9bc0, 0x408a, + 0x188c, 0x2903, 0x9bc0, 0x408a, 0x4141, 0x4583, 0x6465, 0x2803, 0x7c40, + 0xceca, 0x1bcc, 0xc408, 0x0024, 0xf2e2, 0x1bc8, 0x36f1, 0x1805, 0x2000, + 0x0011, 0x36f0, 0x9810, 0x2000, 0x0000, 0xdc92, 0x0024, 0x0006, 0x8a17, + 0x3613, 0x1c00, 0x6093, 0xe1e3, 0x0000, 0x03c3, 0x0006, 0x9f95, 0xb132, + 0x9415, 0x3500, 0xfc01, 0x2803, 0x8695, 0xa306, 0x0024, 0x3009, 0x184c, + 0x3009, 0x3814, 0x0025, 0xffd4, 0x0006, 0xd317, 0x3710, 0x160c, 0x0006, + 0x9f94, 0x37f0, 0x73d5, 0x6c92, 0x3808, 0x3f10, 0x0024, 0x3ff0, 0x4024, + 0x3009, 0x1040, 0x3009, 0x13c1, 0x6010, 0x0024, 0x0000, 0x0024, 0x2903, + 0xc445, 0x0003, 0x8288, 0x2803, 0x84d4, 0x0006, 0x0001, 0x4010, 0x0024, + 0x0005, 0xf601, 0x6010, 0x0024, 0x0000, 0x0040, 0x2803, 0x8654, 0x0030, + 0x0497, 0x3f00, 0x0024, 0x36f2, 0x1814, 0x4330, 0x9803, 0x2000, 0x0000, + 0x8880, 0x1bc1, 0x3613, 0x0024, 0x3e22, 0xb806, 0x3e05, 0xb814, 0x3615, + 0x0024, 0x0000, 0x800a, 0x3e10, 0x3801, 0x3e10, 0xb803, 0x3e11, 0x7807, + 0x6848, 0x930c, 0x3411, 0x780d, 0x459a, 0x10c0, 0x0000, 0x0201, 0x6012, + 0x384e, 0x0000, 0x0241, 0x2803, 0x8dd5, 0x6012, 0x380f, 0x2403, 0x8d05, + 0x0000, 0x0024, 0x3000, 0x0001, 0x3101, 0x8407, 0x6cfe, 0x0024, 0xac42, + 0x0024, 0xaf4e, 0x2040, 0x3911, 0x8024, 0x2803, 0x9980, 0x0000, 0x0024, + 0x0000, 0x0281, 0x2803, 0x9115, 0x6012, 0x4455, 0x2403, 0x9045, 0x0000, + 0x0024, 0x3000, 0x0001, 0x3101, 0x8407, 0x4cf2, 0x0024, 0xac42, 0x0024, + 0xaf4e, 0x2040, 0x3911, 0x8024, 0x2803, 0x9980, 0x0000, 0x0024, 0x0000, + 0x0024, 0x2803, 0x9555, 0x4080, 0x0024, 0x3110, 0x0401, 0xf20f, 0x0203, + 0x2403, 0x9485, 0x8dd6, 0x0024, 0x4dce, 0x0024, 0xf1fe, 0x0024, 0xaf4e, + 0x0024, 0x6dc6, 0x2046, 0xf1df, 0x0203, 0xaf4f, 0x1011, 0xf20e, 0x07cc, + 0x8dd6, 0x2486, 0x2803, 0x9980, 0x0000, 0x0024, 0x0000, 0x0024, 0x2803, + 0x97d5, 0x0000, 0x0024, 0x0fff, 0xffd1, 0x2403, 0x9705, 0x3010, 0x0001, + 0xac4f, 0x0801, 0x3821, 0x8024, 0x2803, 0x9980, 0x0000, 0x0024, 0x0fff, + 0xffd1, 0x2403, 0x9945, 0x3010, 0x0001, 0x3501, 0x9407, 0xac47, 0x0801, + 0xaf4e, 0x2082, 0x3d11, 0x8024, 0x36f3, 0xc024, 0x36f3, 0x980d, 0x36f1, + 0x5807, 0x36f0, 0x9803, 0x36f0, 0x1801, 0x3405, 0x9014, 0x36e3, 0x0024, + 0x2000, 0x0000, 0x36f2, 0x9806, 0x3e10, 0xb812, 0x3e11, 0xb810, 0x3e12, + 0x0024, 0x0006, 0x9f92, 0x0025, 0xffd0, 0x3e04, 0x4bd1, 0x3181, 0xf847, + 0xb68c, 0x4440, 0x3009, 0x0802, 0x6024, 0x3806, 0x0006, 0x8a10, 0x2903, + 0xc445, 0x0003, 0x9dc8, 0x0000, 0x0800, 0x6101, 0x1602, 0xaf2e, 0x0024, + 0x4214, 0x1be3, 0xaf0e, 0x1811, 0x0fff, 0xfc00, 0xb200, 0x9bc7, 0x0000, + 0x03c0, 0x2803, 0xa205, 0xb204, 0xa002, 0x2900, 0xb800, 0x3613, 0x2002, + 0x4680, 0x1bc8, 0x36f1, 0x9810, 0x2000, 0x0000, 0x36f0, 0x9812, 0x0000, + 0x0400, 0x6102, 0x0024, 0x3e11, 0x3805, 0x2803, 0xa609, 0x3e02, 0x0024, + 0x2903, 0x9bc0, 0x408a, 0x188c, 0x2903, 0x9bc0, 0x408a, 0x4141, 0x4582, + 0x1bc8, 0x2000, 0x0000, 0x36f1, 0x1805, 0x2903, 0x9bc0, 0x4102, 0x184c, + 0xb182, 0x1bc8, 0x2000, 0x0000, 0x36f1, 0x1805, 0x2a03, 0xa78e, 0x3e12, + 0xb817, 0x3e10, 0x3802, 0x0000, 0x800a, 0x0006, 0x9f97, 0x3009, 0x1fc2, + 0x3e04, 0x5c00, 0x6020, 0xb810, 0x0030, 0x0451, 0x2803, 0xaa54, 0x0006, + 0x0002, 0x4020, 0x0024, 0x0005, 0xfb02, 0x6024, 0x0024, 0x0025, 0xffd0, + 0x2803, 0xac91, 0x3100, 0x1c11, 0xb284, 0x0024, 0x0030, 0x0490, 0x3800, + 0x8024, 0x0025, 0xffd0, 0x3980, 0x1810, 0x36f4, 0x7c11, 0x36f0, 0x1802, + 0x0030, 0x0717, 0x3602, 0x8024, 0x2100, 0x0000, 0x3f05, 0xdbd7, 0x0003, + 0xa757, 0x3613, 0x0024, 0x3e00, 0x3801, 0xf400, 0x55c0, 0x0000, 0x0897, + 0xf400, 0x57c0, 0x0000, 0x0024, 0x2000, 0x0000, 0x36f0, 0x1801, 0x3613, + 0x0024, 0x3e22, 0xb815, 0x3e05, 0xb814, 0x3615, 0x0024, 0x0000, 0x800a, + 0x3e10, 0x3801, 0x3e10, 0xb803, 0xb884, 0xb805, 0xb88a, 0x3844, 0x3e11, + 0xb80d, 0x3e03, 0xf80e, 0x0000, 0x03ce, 0x2403, 0xb68e, 0xf400, 0x4083, + 0x0000, 0x0206, 0xa562, 0x0024, 0x455a, 0x0024, 0x0020, 0x0006, 0xd312, + 0x0024, 0xb16c, 0x0024, 0x0000, 0x01c6, 0x2803, 0xb685, 0x0000, 0x0024, + 0xd56a, 0x0024, 0x4336, 0x0024, 0x0000, 0x4000, 0x0006, 0x9306, 0x4092, + 0x0024, 0xb512, 0x0024, 0x462c, 0x0024, 0x6294, 0x4195, 0x6200, 0x3401, + 0x0000, 0x03ce, 0x2803, 0xb391, 0xb88a, 0x0024, 0x36f3, 0xd80e, 0x36f1, + 0x980d, 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f0, 0x1801, 0x3405, 0x9014, + 0x36e3, 0x0024, 0x2000, 0x0000, 0x36f2, 0x9815, 0x3613, 0x0024, 0x3e12, + 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3615, 0x0024, 0x0000, 0x800a, + 0x3e10, 0x3801, 0xb880, 0xb810, 0x0006, 0x9fd0, 0x3e10, 0x8001, 0x4182, + 0x3811, 0x0006, 0xd311, 0x2803, 0xbf45, 0x0006, 0x8a10, 0x0000, 0x0200, + 0xbc82, 0xa000, 0x3910, 0x0024, 0x2903, 0xb080, 0x39f0, 0x4024, 0x0006, + 0x9f90, 0x0006, 0x9f51, 0x3009, 0x0000, 0x3009, 0x0401, 0x6014, 0x0024, + 0x0000, 0x0024, 0x2903, 0xc445, 0x0003, 0xc048, 0x36f4, 0x4024, 0x36f0, + 0x9810, 0x36f0, 0x1801, 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, + 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, + 0x3815, 0x3e05, 0xb814, 0x290a, 0xd900, 0x3605, 0x0024, 0x2910, 0x0180, + 0x3613, 0x0024, 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, + 0x0000, 0x36f2, 0x9817, 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, + 0x3e05, 0xb814, 0x3615, 0x0024, 0x0000, 0x800a, 0x3e10, 0xb803, 0x0006, + 0x0002, 0x3e11, 0x3805, 0x3e11, 0xb807, 0x3e14, 0x3811, 0x0006, 0x9f90, + 0x3e04, 0xb813, 0x3009, 0x0012, 0x3213, 0x0024, 0xf400, 0x4480, 0x6026, + 0x0024, 0x0000, 0x0024, 0x2803, 0xccd5, 0x0000, 0x0024, 0x0000, 0x0012, + 0xf400, 0x4480, 0x0006, 0x9f50, 0x3009, 0x0002, 0x6026, 0x0024, 0x0000, + 0x0024, 0x2903, 0xc445, 0x0003, 0xccc8, 0x0006, 0x9f93, 0x3201, 0x0c11, + 0xb58a, 0x0406, 0x0006, 0x8a11, 0x468e, 0x8400, 0xb68c, 0x9813, 0xcfee, + 0x1bd2, 0x0000, 0x0804, 0xaf0e, 0x9811, 0x4f86, 0x1bd0, 0x0000, 0x0021, + 0x6418, 0x9807, 0x6848, 0x1bc6, 0xad46, 0x9805, 0xf400, 0x4080, 0x36f1, + 0x0024, 0x36f0, 0x9803, 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, + 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, + 0x3815, 0x3e05, 0xb814, 0x3615, 0x0024, 0x0000, 0x800a, 0x3e10, 0x3801, + 0x3e10, 0xb803, 0x3e11, 0x3805, 0x2803, 0xdb00, 0x3e04, 0x3811, 0x0000, + 0x0401, 0x2903, 0x9bc0, 0x3613, 0x0024, 0x0000, 0x0080, 0xb882, 0x130c, + 0xf400, 0x4510, 0x3010, 0x910c, 0x30f0, 0xc024, 0x6dc2, 0x0024, 0x3810, + 0x0024, 0x38f0, 0x4024, 0x0000, 0x0201, 0x3100, 0x0024, 0xb010, 0x0024, + 0x0000, 0x0024, 0x2803, 0xde55, 0x0000, 0x0024, 0x6894, 0x130c, 0xb886, + 0x1040, 0x3430, 0x4024, 0x6dca, 0x0024, 0x0030, 0x0011, 0x2803, 0xd6d1, + 0x0000, 0x0024, 0xbcd2, 0x0024, 0x0000, 0x0201, 0x2803, 0xde45, 0x0000, + 0x0024, 0x2903, 0x9bc0, 0x3613, 0x0024, 0x36f4, 0x1811, 0x36f1, 0x1805, + 0x36f0, 0x9803, 0x36f0, 0x1801, 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, + 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, 0x0024, 0x3e12, 0xb815, + 0x0000, 0x800a, 0x3e14, 0x7813, 0x3e10, 0xb803, 0x3e11, 0x3805, 0x3e11, + 0xb807, 0x3e13, 0xf80e, 0x6812, 0x0024, 0x3e03, 0x7810, 0x0fff, 0xffd3, + 0x0000, 0x0091, 0xbd86, 0x9850, 0x3e10, 0x3804, 0x3e00, 0x7812, 0xbe8a, + 0x8bcc, 0x409e, 0x8086, 0x2403, 0xe587, 0xfe49, 0x2821, 0x526a, 0x8801, + 0x5c87, 0x280e, 0x4eba, 0x9812, 0x4286, 0x40e1, 0xb284, 0x1bc1, 0x4de6, + 0x0024, 0xad17, 0x2627, 0x4fde, 0x9804, 0x4498, 0x1bc0, 0x0000, 0x0024, + 0x2803, 0xe395, 0x3a11, 0xa807, 0x36f3, 0x4024, 0x36f3, 0xd80e, 0x36f1, + 0x9807, 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f4, 0x5813, 0x2000, 0x0000, + 0x36f2, 0x9815, 0x3613, 0x0024, 0x3e12, 0xb815, 0x0000, 0x800a, 0x3e10, + 0xb803, 0x3e11, 0x3805, 0x3e11, 0xb807, 0x3e13, 0xf80e, 0x6812, 0x0024, + 0x3e03, 0x7810, 0x3009, 0x1850, 0x3e10, 0x3804, 0x3e10, 0x7812, 0x32f3, + 0x0024, 0xbd86, 0x0024, 0x4091, 0xe2e3, 0x3009, 0x0046, 0x2403, 0xf100, + 0x3009, 0x0047, 0x32f0, 0x0801, 0xfe1f, 0x6465, 0x5e8a, 0x0024, 0x44ba, + 0x0024, 0xfee2, 0x0024, 0x5d8a, 0x1800, 0x4482, 0x4160, 0x48ba, 0x8046, + 0x4dc6, 0x1822, 0x4de6, 0x8047, 0x36f3, 0x0024, 0x36f0, 0x5812, 0xad17, + 0x2627, 0x4fde, 0x9804, 0x4498, 0x1bc0, 0x0000, 0x0024, 0x2803, 0xec95, + 0x3a11, 0xa807, 0x36f3, 0x4024, 0x36f3, 0xd80e, 0x36f1, 0x9807, 0x36f1, + 0x1805, 0x36f0, 0x9803, 0x2000, 0x0000, 0x36f2, 0x9815, 0xb386, 0x40d7, + 0x4284, 0x184c, 0x0000, 0x05c0, 0x2803, 0xf695, 0xf5d8, 0x3804, 0x0000, + 0x0984, 0x6400, 0xb84a, 0x3e13, 0xf80d, 0xa204, 0x380e, 0x0000, 0x800a, + 0x0000, 0x00ce, 0x2403, 0xf9ce, 0xffa4, 0x0024, 0x48b6, 0x0024, 0x0000, + 0x0024, 0x2803, 0xf9c4, 0x4000, 0x40c2, 0x4224, 0x0024, 0x6090, 0x0024, + 0xffa4, 0x0024, 0x0fff, 0xfe83, 0xfe86, 0x1bce, 0x36f3, 0xd80d, 0x48b6, + 0x0024, 0x0fff, 0xff03, 0xa230, 0x45c3, 0x2000, 0x0000, 0x36f1, 0x180a, + 0x4080, 0x184c, 0x3e13, 0x780f, 0x2803, 0xfe05, 0x4090, 0xb80e, 0x2403, + 0xfd80, 0x3e04, 0x0440, 0x3810, 0x0440, 0x3604, 0x0024, 0x3009, 0x1bce, + 0x3603, 0x5bcf, 0x2000, 0x0000, 0x0000, 0x0024, 0x0007, 0x0001, /*copy 1*/ + 0x802e, 0x0006, 0x0002, /*copy 2*/ + 0x2801, 0x6280, 0x0007, 0x0001, /*copy 1*/ + 0x8030, 0x0006, 0x0002, /*copy 2*/ + 0x2800, 0x1440, 0x0007, 0x0001, /*copy 1*/ + 0x8028, 0x0006, 0x0002, /*copy 2*/ + 0x2a00, 0x3c4e, 0x0007, 0x0001, /*copy 1*/ + 0x8032, 0x0006, 0x0002, /*copy 2*/ + 0x2800, 0x59c0, 0x0007, 0x0001, /*copy 1*/ + 0x3580, 0x0006, 0x8038, 0x0000, /*Rle(56)*/ + 0x0007, 0x0001, /*copy 1*/ + 0xfab3, 0x0006, 0x01a4, /*copy 420*/ + 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, 0xffff, 0xfffe, 0xfffb, 0xfff9, + 0xfff5, 0xfff2, 0xffed, 0xffe8, 0xffe3, 0xffde, 0xffd8, 0xffd3, 0xffce, + 0xffca, 0xffc7, 0xffc4, 0xffc4, 0xffc5, 0xffc7, 0xffcc, 0xffd3, 0xffdc, + 0xffe6, 0xfff3, 0x0001, 0x0010, 0x001f, 0x002f, 0x003f, 0x004e, 0x005b, + 0x0066, 0x006f, 0x0074, 0x0075, 0x0072, 0x006b, 0x005f, 0x004f, 0x003c, + 0x0024, 0x0009, 0xffed, 0xffcf, 0xffb0, 0xff93, 0xff77, 0xff5f, 0xff4c, + 0xff3d, 0xff35, 0xff34, 0xff3b, 0xff4a, 0xff60, 0xff7e, 0xffa2, 0xffcd, + 0xfffc, 0x002e, 0x0061, 0x0094, 0x00c4, 0x00f0, 0x0114, 0x0131, 0x0144, + 0x014b, 0x0146, 0x0134, 0x0116, 0x00eb, 0x00b5, 0x0075, 0x002c, 0xffde, + 0xff8e, 0xff3d, 0xfeef, 0xfea8, 0xfe6a, 0xfe39, 0xfe16, 0xfe05, 0xfe06, + 0xfe1b, 0xfe43, 0xfe7f, 0xfecd, 0xff2a, 0xff95, 0x0009, 0x0082, 0x00fd, + 0x0173, 0x01e1, 0x0242, 0x0292, 0x02cc, 0x02ec, 0x02f2, 0x02da, 0x02a5, + 0x0253, 0x01e7, 0x0162, 0x00c9, 0x0021, 0xff70, 0xfebc, 0xfe0c, 0xfd68, + 0xfcd5, 0xfc5b, 0xfc00, 0xfbc9, 0xfbb8, 0xfbd2, 0xfc16, 0xfc85, 0xfd1b, + 0xfdd6, 0xfeae, 0xff9e, 0x009c, 0x01a0, 0x02a1, 0x0392, 0x046c, 0x0523, + 0x05b0, 0x060a, 0x062c, 0x0613, 0x05bb, 0x0526, 0x0456, 0x0351, 0x021f, + 0x00c9, 0xff5a, 0xfde1, 0xfc6a, 0xfb05, 0xf9c0, 0xf8aa, 0xf7d0, 0xf73d, + 0xf6fa, 0xf70f, 0xf77e, 0xf848, 0xf96b, 0xfadf, 0xfc9a, 0xfe8f, 0x00ad, + 0x02e3, 0x051a, 0x073f, 0x0939, 0x0af4, 0x0c5a, 0x0d59, 0x0de1, 0x0de5, + 0x0d5c, 0x0c44, 0x0a9e, 0x0870, 0x05c7, 0x02b4, 0xff4e, 0xfbaf, 0xf7f8, + 0xf449, 0xf0c7, 0xed98, 0xeae0, 0xe8c4, 0xe765, 0xe6e3, 0xe756, 0xe8d2, + 0xeb67, 0xef19, 0xf3e9, 0xf9cd, 0x00b5, 0x088a, 0x112b, 0x1a72, 0x2435, + 0x2e42, 0x3866, 0x426b, 0x4c1b, 0x553e, 0x5da2, 0x6516, 0x6b6f, 0x7087, + 0x7441, 0x7686, 0x774a, 0x7686, 0x7441, 0x7087, 0x6b6f, 0x6516, 0x5da2, + 0x553e, 0x4c1b, 0x426b, 0x3866, 0x2e42, 0x2435, 0x1a72, 0x112b, 0x088a, + 0x00b5, 0xf9cd, 0xf3e9, 0xef19, 0xeb67, 0xe8d2, 0xe756, 0xe6e3, 0xe765, + 0xe8c4, 0xeae0, 0xed98, 0xf0c7, 0xf449, 0xf7f8, 0xfbaf, 0xff4e, 0x02b4, + 0x05c7, 0x0870, 0x0a9e, 0x0c44, 0x0d5c, 0x0de5, 0x0de1, 0x0d59, 0x0c5a, + 0x0af4, 0x0939, 0x073f, 0x051a, 0x02e3, 0x00ad, 0xfe8f, 0xfc9a, 0xfadf, + 0xf96b, 0xf848, 0xf77e, 0xf70f, 0xf6fa, 0xf73d, 0xf7d0, 0xf8aa, 0xf9c0, + 0xfb05, 0xfc6a, 0xfde1, 0xff5a, 0x00c9, 0x021f, 0x0351, 0x0456, 0x0526, + 0x05bb, 0x0613, 0x062c, 0x060a, 0x05b0, 0x0523, 0x046c, 0x0392, 0x02a1, + 0x01a0, 0x009c, 0xff9e, 0xfeae, 0xfdd6, 0xfd1b, 0xfc85, 0xfc16, 0xfbd2, + 0xfbb8, 0xfbc9, 0xfc00, 0xfc5b, 0xfcd5, 0xfd68, 0xfe0c, 0xfebc, 0xff70, + 0x0021, 0x00c9, 0x0162, 0x01e7, 0x0253, 0x02a5, 0x02da, 0x02f2, 0x02ec, + 0x02cc, 0x0292, 0x0242, 0x01e1, 0x0173, 0x00fd, 0x0082, 0x0009, 0xff95, + 0xff2a, 0xfecd, 0xfe7f, 0xfe43, 0xfe1b, 0xfe06, 0xfe05, 0xfe16, 0xfe39, + 0xfe6a, 0xfea8, 0xfeef, 0xff3d, 0xff8e, 0xffde, 0x002c, 0x0075, 0x00b5, + 0x00eb, 0x0116, 0x0134, 0x0146, 0x014b, 0x0144, 0x0131, 0x0114, 0x00f0, + 0x00c4, 0x0094, 0x0061, 0x002e, 0xfffc, 0xffcd, 0xffa2, 0xff7e, 0xff60, + 0xff4a, 0xff3b, 0xff34, 0xff35, 0xff3d, 0xff4c, 0xff5f, 0xff77, 0xff93, + 0xffb0, 0xffcf, 0xffed, 0x0009, 0x0024, 0x003c, 0x004f, 0x005f, 0x006b, + 0x0072, 0x0075, 0x0074, 0x006f, 0x0066, 0x005b, 0x004e, 0x003f, 0x002f, + 0x001f, 0x0010, 0x0001, 0xfff3, 0xffe6, 0xffdc, 0xffd3, 0xffcc, 0xffc7, + 0xffc5, 0xffc4, 0xffc4, 0xffc7, 0xffca, 0xffce, 0xffd3, 0xffd8, 0xffde, + 0xffe3, 0xffe8, 0xffed, 0xfff2, 0xfff5, 0xfff9, 0xfffb, 0xfffe, 0xffff, + 0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, 0x0007, 0x0001, /*copy 1*/ + 0x180b, 0x0006, 0x000b, /*copy 11*/ + 0x000f, 0x0010, 0x001c, 0xfab3, 0x3580, 0x8037, 0xa037, 0x0001, 0x0000, + 0x3580, 0x01a4, 0x0007, 0x0001, /*copy 1*/ + 0x181a, 0x0006, 0x0002, /*copy 2*/ + 0x08b4, 0x08d2, 0x0006, 0x8006, 0x091a, /*Rle(6)*/ + 0x0006, 0x0025, /*copy 37*/ + 0x08ef, 0x08ef, 0x08ef, 0x08ef, 0x08ef, 0x0b11, 0x0af5, 0x0af9, 0x0afd, + 0x0b01, 0x0b05, 0x0b09, 0x0b0d, 0x0b40, 0x0b44, 0x0b47, 0x0b47, 0x0b47, + 0x0b47, 0x0b4f, 0x0b62, 0x0c2d, 0x0b99, 0x0b9e, 0x0ba4, 0x0baa, 0x0baf, + 0x0bb4, 0x0bb9, 0x0bbe, 0x0bc3, 0x0bc8, 0x0bcd, 0x0bd2, 0x0beb, 0x0c0a, + 0x0c29, 0x0007, 0x0001, /*copy 1*/ + 0x5800, 0x0006, 0x0001, /*copy 1*/ + 0x0001, 0x0006, 0x8007, 0x0000, /*Rle(7)*/ + 0x0006, 0x0018, /*copy 24*/ + 0x0002, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0003, + 0x0000, 0xfffd, 0xffff, 0x0001, 0x0000, 0x0000, 0x0000, 0x0004, 0x0000, + 0xfffa, 0xffff, 0x0004, 0x0000, 0xffff, 0xffff, 0x000a, 0x0001, /*copy 1*/ + 0x0050, +#define PLUGIN_SIZE 8588 +#ifndef SKIP_PLUGIN_VARNAME +}; +#endif diff --git a/targets/esp32/components/VS1053/include/patches_latm.h b/targets/esp32/components/VS1053/include/patches_latm.h new file mode 100644 index 00000000..115525f1 --- /dev/null +++ b/targets/esp32/components/VS1053/include/patches_latm.h @@ -0,0 +1,644 @@ + +#ifndef SKIP_PLUGIN_VARNAME +const unsigned short PLUGIN[] = { + /* Compressed plugin */ +#endif + 0x0007, 0x0001, /*copy 1*/ + 0x8050, 0x0006, 0x001e, /*copy 30*/ + 0x2a00, 0xc000, 0x3e12, 0xb817, 0x3e14, 0xf812, 0x3e01, 0xb811, 0x0007, + 0x9717, 0x0020, 0xffd2, 0x0030, 0x11d1, 0x3111, 0x8024, 0x3704, 0xc024, + 0x3b81, 0x8024, 0x3101, 0x8024, 0x3b81, 0x8024, 0x3f04, 0xc024, 0x2808, + 0x4800, 0x36f1, 0x9811, 0x0007, 0x0001, /*copy 1*/ + 0x8060, 0x0006, 0x0536, /*copy 1334*/ + 0xf400, 0x4095, 0x0000, 0x02c2, 0x6124, 0x0024, 0x0000, 0x0024, 0x2800, + 0x1ac5, 0x4192, 0x4542, 0x0000, 0x0041, 0x2000, 0x0015, 0x0030, 0x0317, + 0x2000, 0x0000, 0x3f00, 0x4024, 0x2000, 0x0000, 0x0000, 0x0000, 0x3e12, + 0x3800, 0x3e00, 0xb804, 0x0030, 0x0015, 0x0007, 0x8257, 0x3700, 0x984c, + 0xf224, 0x1444, 0xf224, 0x0024, 0x0008, 0x0002, 0x2910, 0x0181, 0x0000, + 0x1bc8, 0xb428, 0x1402, 0x0000, 0x8004, 0x2910, 0x0195, 0x0000, 0x1bc8, + 0xb428, 0x0024, 0x0006, 0x0095, 0x2800, 0x2945, 0x3e13, 0x780e, 0x3e11, + 0x7803, 0x3e13, 0xf806, 0x3e11, 0xf801, 0x3510, 0xb808, 0x003f, 0xe004, + 0xfec4, 0x3800, 0x48be, 0x17c3, 0xfec6, 0x41c2, 0x48be, 0x4497, 0x4090, + 0x1c46, 0xf06c, 0x0024, 0x2400, 0x2580, 0x6090, 0x41c3, 0x6628, 0x1c47, + 0x0000, 0x0024, 0x2800, 0x2449, 0xf07e, 0x0024, 0xf400, 0x4182, 0x673a, + 0x1c46, 0x0000, 0x0024, 0x2800, 0x2589, 0xf06c, 0x0024, 0xf400, 0x41c3, + 0x0000, 0x0024, 0x4224, 0x3442, 0x2900, 0xb7c0, 0x4336, 0x37c3, 0x0000, + 0x1805, 0x2900, 0xb7c0, 0x4508, 0x40c2, 0x450a, 0x9808, 0x0000, 0x0207, + 0xa478, 0x1bc0, 0xc45a, 0x1807, 0x0030, 0x03d5, 0x3d01, 0x5bc1, 0x36f3, + 0xd806, 0x3601, 0x5803, 0x36f3, 0x0024, 0x36f3, 0x580e, 0x0007, 0x8257, + 0x0000, 0x6004, 0x3730, 0x8024, 0xb244, 0x1c04, 0xd428, 0x3c02, 0x0006, + 0xc717, 0x2800, 0x2d05, 0x4284, 0x0024, 0x3613, 0x3c02, 0x0006, 0xc357, + 0x2901, 0x6480, 0x3e11, 0x5c05, 0x4284, 0x1bc5, 0x0000, 0x0024, 0x2800, + 0x3045, 0x0000, 0x0024, 0x0030, 0x0117, 0x3f00, 0x0024, 0x3613, 0x0024, + 0x3e10, 0x3813, 0x3e14, 0x8024, 0x3e04, 0x8024, 0x2900, 0x4900, 0x0006, + 0x02d3, 0x36e3, 0x0024, 0x3009, 0x1bd3, 0x0007, 0x8257, 0x3700, 0x8024, + 0xf224, 0x0024, 0x0000, 0x0024, 0x2800, 0x3251, 0x3600, 0x9844, 0x2900, + 0x3800, 0x0000, 0x32c8, 0x2911, 0xf140, 0x0000, 0x0024, 0x0030, 0x0057, + 0x3700, 0x0024, 0xf200, 0x4595, 0x0fff, 0xfe02, 0xa024, 0x164c, 0x8000, + 0x17cc, 0x3f00, 0x0024, 0x3500, 0x0024, 0x0021, 0x6d82, 0xd024, 0x44c0, + 0x0006, 0xa402, 0x2800, 0x3715, 0xd024, 0x0024, 0x0000, 0x0000, 0x2800, + 0x3715, 0x000b, 0x6d57, 0x3009, 0x3c00, 0x36f0, 0x8024, 0x36f2, 0x1800, + 0x2000, 0x0000, 0x0000, 0x0024, 0x3e14, 0x7810, 0x3e13, 0xb80d, 0x3e13, + 0xf80a, 0x3e10, 0xb803, 0x3e11, 0x3805, 0x3e11, 0xb807, 0x3e14, 0xf801, + 0x3e15, 0x3815, 0x0001, 0x000a, 0x0006, 0xc4d7, 0xbf8e, 0x9c42, 0x3e01, + 0x9c03, 0x0006, 0xa017, 0x0023, 0xffd1, 0x0007, 0x8250, 0x0fff, 0xfd85, + 0x3001, 0x0024, 0xa45a, 0x4494, 0x0000, 0x0093, 0x2800, 0x3e51, 0xf25a, + 0x104c, 0x34f3, 0x0024, 0x2800, 0x3e51, 0x0000, 0x0024, 0x3413, 0x084c, + 0x0000, 0x0095, 0x3281, 0xf806, 0x4091, 0x4d64, 0x2400, 0x4080, 0x4efa, + 0x9c10, 0xf1eb, 0x6061, 0xfe55, 0x2f66, 0x5653, 0x4d64, 0x48b2, 0xa201, + 0x4efa, 0xa201, 0x36f3, 0x3c10, 0x36f5, 0x1815, 0x36f4, 0xd801, 0x36f1, + 0x9807, 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f3, 0xd80a, 0x36f3, 0x980d, + 0x2000, 0x0000, 0x36f4, 0x5810, 0x36f3, 0x0024, 0x3009, 0x3848, 0x3e14, + 0x3811, 0x3e00, 0x0024, 0x0000, 0x4000, 0x0001, 0x0010, 0x2915, 0x94c0, + 0x0001, 0xcc11, 0x36f0, 0x0024, 0x2927, 0x9e40, 0x3604, 0x1811, 0x3613, + 0x0024, 0x3e14, 0x3811, 0x3e00, 0x0024, 0x0000, 0x4000, 0x0001, 0x0010, + 0x2915, 0x94c0, 0x0001, 0xcc11, 0x36f0, 0x0024, 0x36f4, 0x1811, 0x3009, + 0x1808, 0x2000, 0x0000, 0x0000, 0x190d, 0x3613, 0x0024, 0x3e22, 0xb815, + 0x3e05, 0xb814, 0x3615, 0x0024, 0x0000, 0x800a, 0x3e13, 0x7801, 0x3e10, + 0xb803, 0x3e11, 0x3805, 0x3e11, 0xb807, 0x3e14, 0x3811, 0x3e14, 0xb813, + 0x3e03, 0xf80e, 0xb488, 0x44d5, 0x3543, 0x134c, 0x34e5, 0xc024, 0x3524, + 0x8024, 0x35a4, 0xc024, 0x3710, 0x8a0c, 0x3540, 0x4a0c, 0x3d44, 0x8024, + 0x3a10, 0x8024, 0x3590, 0x0024, 0x4010, 0x15c1, 0x6010, 0x3400, 0x3710, + 0x8024, 0x2800, 0x54c4, 0x3af0, 0x8024, 0x3df0, 0x0024, 0x3591, 0x4024, + 0x3530, 0x4024, 0x4192, 0x4050, 0x6100, 0x1482, 0x4020, 0x1753, 0xbf8e, + 0x1582, 0x4294, 0x4011, 0xbd86, 0x408e, 0x2400, 0x52ce, 0xfe6d, 0x2819, + 0x520e, 0x0a00, 0x5207, 0x2819, 0x4fbe, 0x0024, 0xad56, 0x904c, 0xaf5e, + 0x1010, 0xf7d4, 0x0024, 0xf7fc, 0x2042, 0x6498, 0x2046, 0x3cf4, 0x0024, + 0x3400, 0x170c, 0x4090, 0x1492, 0x35a4, 0xc024, 0x2800, 0x4d55, 0x3c00, + 0x0024, 0x4480, 0x914c, 0x36f3, 0xd80e, 0x36f4, 0x9813, 0x36f4, 0x1811, + 0x36f1, 0x9807, 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f3, 0x5801, 0x3405, + 0x9014, 0x36e3, 0x0024, 0x2000, 0x0000, 0x36f2, 0x9815, 0x2814, 0x9c91, + 0x0000, 0x004d, 0x2814, 0x9940, 0x003f, 0x0013, 0x3613, 0x0024, 0x3e12, + 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3655, 0x0024, 0x0000, 0x800a, + 0x3e10, 0x3801, 0x3e10, 0xb803, 0x3e11, 0x3805, 0x3e11, 0xb810, 0x3e13, + 0xf80e, 0x3e03, 0x534c, 0x3450, 0x4024, 0x6814, 0x0024, 0x0000, 0x0024, + 0x2800, 0x73d8, 0x4192, 0x0024, 0x2400, 0x7381, 0x0000, 0x0024, 0xf400, + 0x4450, 0x2938, 0x1880, 0x3613, 0x0024, 0x3c10, 0x050c, 0x3c10, 0x4024, + 0x3c90, 0x8024, 0x34f3, 0x0024, 0x3464, 0x0024, 0x3011, 0x0c40, 0x3011, + 0x4c41, 0x2915, 0x9900, 0x3011, 0x8f82, 0x3411, 0x2c40, 0x3411, 0x6c41, + 0x2915, 0xa580, 0x34e1, 0xaf82, 0x3009, 0x3040, 0x4c8a, 0x0040, 0x3010, + 0x7041, 0x2800, 0x6614, 0x3010, 0xb382, 0x3411, 0x0024, 0x3411, 0x6c44, + 0x34e1, 0xac45, 0xbe8a, 0xaf86, 0x0fe0, 0x0006, 0x3009, 0x3044, 0x3009, + 0x3045, 0x3009, 0x3386, 0x3411, 0x0024, 0x3411, 0x4ccc, 0x2915, 0x9900, + 0x34e1, 0x984c, 0x3e10, 0x7800, 0x3009, 0x3802, 0x3011, 0x0c40, 0x3011, + 0x4c41, 0x2915, 0x9900, 0x30e1, 0x8f82, 0x3009, 0x1bc6, 0x2915, 0xa940, + 0x36f1, 0x5804, 0x3011, 0x2c40, 0x3011, 0x6c41, 0x30b1, 0xac42, 0x3009, + 0x0c40, 0x3009, 0x0c41, 0x2915, 0x9900, 0x3613, 0x0f82, 0x3e10, 0x7800, + 0x3009, 0x3802, 0x3010, 0x1044, 0x3010, 0x5045, 0x2915, 0x9900, 0x3010, + 0x9386, 0x3009, 0x1bc6, 0x2915, 0xa940, 0x36f1, 0x5804, 0xf1ca, 0xac40, + 0x4ce2, 0xac41, 0x3009, 0x2ec2, 0x2800, 0x6ed2, 0x629c, 0x0024, 0xf1c2, + 0x4182, 0x3c10, 0x0c44, 0x3c10, 0x4c45, 0x2915, 0x4780, 0x3ce0, 0x8f86, + 0x4080, 0x0024, 0x0000, 0x0024, 0x2800, 0x7395, 0x0020, 0x0000, 0x3411, + 0x0c40, 0x3411, 0x4c41, 0x2915, 0xb780, 0x34e1, 0x8f82, 0x0000, 0x03c3, + 0x4234, 0x0024, 0x4c82, 0x0024, 0x0000, 0x0024, 0x2915, 0x4355, 0x0000, + 0x7388, 0x0000, 0x0000, 0x3a10, 0x0d8c, 0x36f3, 0x538c, 0x36f3, 0xd80e, + 0x36f1, 0x9810, 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f0, 0x1801, 0x3405, + 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, + 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3645, + 0x0024, 0x0000, 0x800a, 0x3e10, 0x3801, 0x3e10, 0xb803, 0x3e11, 0x3805, + 0x3e11, 0xb810, 0x3e13, 0xf80e, 0x3e03, 0x534c, 0x3440, 0x4024, 0x4192, + 0x0024, 0x2400, 0x8f81, 0x0000, 0x0024, 0xb68c, 0x4450, 0x2938, 0x1880, + 0x3613, 0x050c, 0x3c10, 0x0c40, 0x3c10, 0x4c41, 0x3ce0, 0x8f82, 0x003c, + 0x2584, 0x2915, 0x9900, 0x0018, 0x8245, 0x3411, 0x2c40, 0x3411, 0x6c41, + 0x2915, 0xa580, 0x34e1, 0xac42, 0x4c8a, 0xb040, 0x3009, 0x3041, 0x2800, + 0x8094, 0x3009, 0x3382, 0x3411, 0x0f4c, 0x3411, 0x6c44, 0x34e1, 0xac45, + 0xbe8a, 0xac46, 0x499c, 0xb044, 0xf38c, 0xb045, 0x3009, 0x3386, 0x3009, + 0x0c40, 0x3009, 0x0c41, 0xf1ca, 0x8f82, 0x4ce2, 0x1044, 0x3411, 0x4024, + 0x2800, 0x82d2, 0x4294, 0x1386, 0x6294, 0x0024, 0xf1c2, 0x0024, 0x4e8a, + 0x4195, 0x35e3, 0x0024, 0x2915, 0xa955, 0xf400, 0x4546, 0x3009, 0x2c40, + 0x3009, 0x2c41, 0x3009, 0x2c42, 0x3009, 0x0c40, 0x3009, 0x0c41, 0xf1ca, + 0x8f82, 0x4ce2, 0x9044, 0x3009, 0x1045, 0x2800, 0x8745, 0x3009, 0x1386, + 0x2800, 0x8752, 0x4294, 0x0024, 0x6294, 0x0024, 0xf1c2, 0x0024, 0x4e8a, + 0x4195, 0x35e3, 0x0024, 0x2915, 0xa955, 0xf400, 0x4546, 0xf1ca, 0xac40, + 0x4ce2, 0xac41, 0x3009, 0x2ec2, 0x2800, 0x89d2, 0x629c, 0x0024, 0xf1c2, + 0x4182, 0x3c20, 0x0c84, 0x3cf0, 0x8fc6, 0x6264, 0x4017, 0x3cf0, 0x4fc5, + 0x2800, 0x8f88, 0x0020, 0x0000, 0x2800, 0x8cd9, 0xf400, 0x45c0, 0x6cea, + 0x0024, 0x0000, 0x0024, 0x2800, 0x8f89, 0x0020, 0x0000, 0x3411, 0x0c40, + 0x3411, 0x4c41, 0x2915, 0xb780, 0x34e1, 0x8f82, 0x0000, 0x03c3, 0x4234, + 0x0024, 0x4c82, 0x0024, 0x0000, 0x0024, 0x2915, 0x4355, 0x0000, 0x8f88, + 0x0000, 0x0000, 0x3a10, 0x0d8c, 0x36f3, 0x53cc, 0x36f3, 0xd80e, 0x36f1, + 0x9810, 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f0, 0x1801, 0x3405, 0x9014, + 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0xf400, + 0x4595, 0x35e3, 0x3840, 0x3e13, 0xf80e, 0x3e13, 0x7808, 0x3510, 0x0024, + 0x3e10, 0x0024, 0x3510, 0x0024, 0x3e10, 0x0024, 0x3510, 0x0024, 0x3e00, + 0x0024, 0x0001, 0xb0ce, 0x002b, 0xb30f, 0x292d, 0xa940, 0x0000, 0x004d, + 0x36d3, 0x0024, 0x36f3, 0x5808, 0x36f3, 0xd80e, 0x2000, 0x0000, 0x3009, + 0x1800, 0xf400, 0x4595, 0x35f3, 0x3840, 0x3e13, 0xf80e, 0x3e13, 0x7808, + 0x3510, 0x0024, 0x3e10, 0x0024, 0x3510, 0x0024, 0x3e00, 0x0024, 0x0000, + 0x9b8e, 0x0028, 0x088f, 0x2927, 0xff80, 0x0000, 0x008d, 0x36e3, 0x0024, + 0x36f3, 0x5808, 0x36f3, 0xd80e, 0x2000, 0x0000, 0x3009, 0x1800, 0x0028, + 0x2b0f, 0x0000, 0xa10e, 0x2828, 0x0b15, 0x0007, 0x2605, 0x3613, 0x0001, + 0x3e14, 0x3811, 0x0001, 0x0011, 0x0001, 0xcc10, 0x2915, 0x94c0, 0x0000, + 0x4000, 0x3e10, 0x534c, 0x3430, 0xc024, 0x3e10, 0xc024, 0x2927, 0xc4c0, + 0x3e01, 0x0024, 0x36d3, 0x0024, 0x0001, 0x0011, 0x0001, 0xcc10, 0x2915, + 0x94c0, 0x0000, 0x4000, 0x2828, 0x0b00, 0x36f4, 0x1811, 0x3e00, 0x0024, + 0x2800, 0xa500, 0x0028, 0x2bc8, 0x3605, 0x7840, 0x3e13, 0x780e, 0x3e13, + 0xf808, 0x3e05, 0x4024, 0x0000, 0x434e, 0x0027, 0x9e0f, 0x2922, 0xa6c0, + 0x0000, 0x190d, 0x36f3, 0x0024, 0x36f3, 0xd808, 0x36f3, 0x580e, 0x2000, + 0x0000, 0x3009, 0x1800, 0xf400, 0x4595, 0x35d3, 0x3840, 0x3e13, 0xf80e, + 0x3e13, 0x7808, 0x3510, 0x0024, 0x3e10, 0x0024, 0x3510, 0x0024, 0x3e10, + 0x0024, 0x3510, 0x0024, 0x3e10, 0x0024, 0x3510, 0x0024, 0x3e00, 0x0024, + 0x0000, 0xaa4e, 0x0025, 0xf54f, 0x2925, 0xe580, 0x0000, 0x004d, 0x36c3, + 0x0024, 0x36f3, 0x5808, 0x36f3, 0xd80e, 0x2000, 0x0000, 0x3009, 0x1800, + 0x3433, 0x0000, 0x6890, 0x3040, 0x3cc0, 0xa000, 0x0008, 0x6201, 0x000d, + 0x3500, 0x3613, 0x110c, 0x3e10, 0x0024, 0x3e10, 0x4024, 0x34c0, 0x8024, + 0x2900, 0x9280, 0x3e00, 0x8024, 0x0026, 0x0a4f, 0x0000, 0xae0e, 0x2825, + 0xf880, 0x0000, 0x07cd, 0x0000, 0x0801, 0x6012, 0x0024, 0x0000, 0x0024, + 0x2826, 0x0a85, 0x0000, 0x0024, 0x2800, 0xab00, 0x0000, 0x0024, 0x3605, + 0x7840, 0x3e13, 0x780e, 0x3e13, 0xf808, 0x3e05, 0x4024, 0x0000, 0xb30e, + 0x0022, 0xf54f, 0x2922, 0xda80, 0x0000, 0x190d, 0x36f3, 0x0024, 0x36f3, + 0xd808, 0x36f3, 0x580e, 0x2000, 0x0000, 0x3009, 0x1800, 0x3e00, 0x0024, + 0x2800, 0x9740, 0x0022, 0xf608, 0x3605, 0x7840, 0x3e13, 0x780e, 0x3e13, + 0xf808, 0x3e05, 0x4024, 0x0000, 0xb70e, 0x0022, 0xa1cf, 0x2922, 0x9980, + 0x0000, 0x190d, 0x36f3, 0x0024, 0x36f3, 0xd808, 0x36f3, 0x580e, 0x2000, + 0x0000, 0x3009, 0x1800, 0x3009, 0x3400, 0x2800, 0xafc0, 0x0022, 0xa288, + 0xb386, 0x40d7, 0x4284, 0x184c, 0x0000, 0x05c0, 0x2800, 0xb955, 0xf5d8, + 0x3804, 0x0000, 0x0984, 0x6400, 0xb84a, 0x3e13, 0xf80d, 0xa204, 0x380e, + 0x0000, 0x800a, 0x0000, 0x00ce, 0x2400, 0xbc8e, 0xffa4, 0x0024, 0x48b6, + 0x0024, 0x0000, 0x0024, 0x2800, 0xbc84, 0x4000, 0x40c2, 0x4224, 0x0024, + 0x6090, 0x0024, 0xffa4, 0x0024, 0x0fff, 0xfe83, 0xfe86, 0x1bce, 0x36f3, + 0xd80d, 0x48b6, 0x0024, 0x0fff, 0xff03, 0xa230, 0x45c3, 0x2000, 0x0000, + 0x36f1, 0x180a, 0x0007, 0x0001, /*copy 1*/ + 0x8300, 0x0006, 0x0e92, /*copy 3730*/ + 0x0030, 0x0055, 0xb080, 0x1402, 0x0fdf, 0xffc1, 0x0007, 0x9257, 0xb212, + 0x3c00, 0x3d00, 0x4024, 0x0006, 0x0097, 0x3f10, 0x0024, 0x3f00, 0x0024, + 0x0030, 0x0297, 0x3f00, 0x0024, 0x0007, 0x9017, 0x3f00, 0x0024, 0x0007, + 0x81d7, 0x3f10, 0x0024, 0xc090, 0x3c00, 0x0006, 0x0297, 0xb080, 0x3c00, + 0x0000, 0x0401, 0x000a, 0x1055, 0x0006, 0x0017, 0x3f10, 0x3401, 0x000a, + 0x2795, 0x3f00, 0x3401, 0x0001, 0x6457, 0xf400, 0x55c0, 0x0000, 0x0817, + 0xb080, 0x57c0, 0x0014, 0x958f, 0x0000, 0x590e, 0x0030, 0x0017, 0x3700, + 0x0024, 0x0004, 0x0001, 0xb012, 0x0024, 0x0000, 0x004d, 0x280f, 0xe115, + 0x0006, 0x2016, 0x0006, 0x01d7, 0x3f00, 0x0024, 0x0000, 0x190d, 0x000f, + 0xf94f, 0x0000, 0xcd0e, 0x280f, 0xe100, 0x0006, 0x2016, 0x0000, 0x0080, + 0x0005, 0x4f92, 0x2909, 0xf840, 0x3613, 0x2800, 0x0006, 0x0197, 0x0006, + 0xa115, 0xb080, 0x0024, 0x3f00, 0x3400, 0x0007, 0x8a57, 0x3700, 0x0024, + 0x4080, 0x0024, 0x0000, 0x0040, 0x2800, 0xced5, 0x0006, 0xa2d7, 0x3009, + 0x3c00, 0x0006, 0xa157, 0x3009, 0x1c00, 0x0006, 0x01d7, 0x0000, 0x190d, + 0x000a, 0x708f, 0x0000, 0xd7ce, 0x290b, 0x1a80, 0x3f00, 0x184c, 0x0030, + 0x0017, 0x4080, 0x1c01, 0x0000, 0x0200, 0x2800, 0xcb15, 0xb102, 0x0024, + 0x0000, 0xcd08, 0x2800, 0xcb15, 0x0000, 0xd3ce, 0x0011, 0x210f, 0x0000, + 0x190d, 0x280f, 0xcb00, 0x3613, 0x0024, 0x0006, 0xa115, 0x0006, 0x01d7, + 0x37f0, 0x1401, 0x6100, 0x1c01, 0x4012, 0x0024, 0x0000, 0x8000, 0x6010, + 0x0024, 0x34f3, 0x0400, 0x2800, 0xd698, 0x0000, 0x0024, 0x0000, 0x8001, + 0x6010, 0x3c01, 0x0000, 0x000d, 0x2811, 0x8259, 0x0000, 0x0024, 0x2a11, + 0x2100, 0x0030, 0x0257, 0x3700, 0x0024, 0x4080, 0x0024, 0x0000, 0x0024, + 0x2800, 0xd9d5, 0x0006, 0x0197, 0x0006, 0xa115, 0x3f00, 0x3400, 0x003f, + 0xc000, 0xb600, 0x41c1, 0x0012, 0x5103, 0x000c, 0xc002, 0xdcd6, 0x0024, + 0x0019, 0xd4c2, 0x2802, 0x8345, 0x0001, 0x0988, 0x0013, 0xd9c3, 0x6fd6, + 0x0024, 0x0000, 0x190d, 0x2800, 0xdf95, 0x0014, 0x1b01, 0x0020, 0x480f, + 0x0000, 0xde4e, 0x0000, 0x190d, 0x2820, 0x41c0, 0x0001, 0x0988, 0x0039, + 0x324f, 0x0001, 0x384e, 0x2820, 0x4a18, 0xb882, 0x0024, 0x2a20, 0x48c0, + 0x003f, 0xfd00, 0xb700, 0x0024, 0x003f, 0xf901, 0x6010, 0x0024, 0x0000, + 0x0024, 0x280a, 0xc505, 0x0000, 0x190d, 0x2a00, 0xe180, 0x000a, 0x8c8f, + 0x0000, 0xe2ce, 0x000c, 0x0981, 0x280a, 0x71c0, 0x002c, 0x9d40, 0x000a, + 0x708f, 0x0000, 0xd7ce, 0x280a, 0xc0d5, 0x0012, 0x5182, 0x6fd6, 0x0024, + 0x003f, 0xfd81, 0x280a, 0x8e45, 0xb710, 0x0024, 0x003f, 0xf800, 0xb600, + 0x0024, 0x0015, 0xb801, 0x6012, 0x0024, 0x003f, 0xfd81, 0x2802, 0x4ec5, + 0x0001, 0x0a88, 0xb710, 0x0024, 0x003f, 0xfc01, 0x6012, 0x0024, 0x0000, + 0x0101, 0x2801, 0x0055, 0xffd2, 0x0024, 0x48b2, 0x0024, 0x4190, 0x0024, + 0x0000, 0x190d, 0x2801, 0x0055, 0x0030, 0x0250, 0xb880, 0x104c, 0x3cf0, + 0x0024, 0x0010, 0x5500, 0xb880, 0x23c0, 0xb882, 0x2000, 0x0007, 0x8590, + 0x2914, 0xbec0, 0x0000, 0x0440, 0x0007, 0x8b50, 0xb880, 0x0024, 0x2920, + 0x0100, 0x3800, 0x0024, 0x2920, 0x0000, 0x0006, 0x8a91, 0x0000, 0x0800, + 0xb880, 0xa440, 0x003f, 0xfd81, 0xb710, 0xa7c0, 0x003f, 0xfc01, 0x6012, + 0x0024, 0x0000, 0x0101, 0x2801, 0x0995, 0x0000, 0x0024, 0xffe2, 0x0024, + 0x48b2, 0x0024, 0x4190, 0x0024, 0x0000, 0x0024, 0x2801, 0x0995, 0x0000, + 0x0024, 0x2912, 0x2d80, 0x0000, 0x0780, 0x4080, 0x0024, 0x0006, 0x8a90, + 0x2801, 0x0995, 0x0000, 0x01c2, 0xb886, 0x8040, 0x3613, 0x03c1, 0xbcd2, + 0x0024, 0x0030, 0x0011, 0x2800, 0xf615, 0x003f, 0xff42, 0xb886, 0x8040, + 0x3009, 0x03c1, 0x0000, 0x0020, 0xac22, 0x0024, 0x0000, 0x0102, 0x6cd2, + 0x0024, 0x3e10, 0x0024, 0x2909, 0x8c80, 0x3e00, 0x4024, 0x36f3, 0x0024, + 0x3e11, 0x8024, 0x3e01, 0xc024, 0x2901, 0x2e40, 0x0000, 0x0201, 0xf400, + 0x4512, 0x2900, 0x0c80, 0x3213, 0x1b8c, 0x3100, 0x0024, 0xb010, 0x0024, + 0x0000, 0x0024, 0x2801, 0x0995, 0x0000, 0x0024, 0x291a, 0x8a40, 0x0000, + 0x0100, 0x2920, 0x0200, 0x3633, 0x0024, 0x2920, 0x0280, 0x0000, 0x0401, + 0x408e, 0x0024, 0x2920, 0x0280, 0x0000, 0x0401, 0x003f, 0xfd81, 0xb710, + 0x4006, 0x003f, 0xfc01, 0x6012, 0x0024, 0x0000, 0x0101, 0x2801, 0x0995, + 0x0000, 0x0024, 0xffe2, 0x0024, 0x48b2, 0x0024, 0x4190, 0x0024, 0x0000, + 0x0024, 0x2801, 0x0995, 0x0000, 0x0024, 0x2912, 0x2d80, 0x0000, 0x0780, + 0x4080, 0x0024, 0x0000, 0x01c2, 0x2800, 0xf205, 0x0006, 0x8a90, 0x2a01, + 0x0980, 0x2920, 0x0100, 0x0000, 0x0401, 0x0000, 0x0180, 0x2920, 0x0200, + 0x3613, 0x0024, 0x2920, 0x0280, 0x3613, 0x0024, 0x0000, 0x0401, 0x2920, + 0x0280, 0x4084, 0x984c, 0x0019, 0x9d01, 0x6212, 0x0024, 0x001e, 0x5c01, + 0x2801, 0x04d5, 0x6012, 0x0024, 0x0000, 0x0024, 0x2801, 0x06c5, 0x0000, + 0x0024, 0x001b, 0x5bc1, 0x6212, 0x0024, 0x001b, 0xdd81, 0x2801, 0x0a95, + 0x6012, 0x0024, 0x0000, 0x0024, 0x2801, 0x0a95, 0x0000, 0x0024, 0x0000, + 0x004d, 0x000a, 0xbf4f, 0x280a, 0xb880, 0x0001, 0x07ce, 0x0020, 0xfb4f, + 0x0000, 0x190d, 0x0001, 0x0ece, 0x2920, 0xf440, 0x3009, 0x2bc1, 0x291a, + 0x8a40, 0x36e3, 0x0024, 0x0000, 0x190d, 0x000a, 0x708f, 0x280a, 0xcac0, + 0x0000, 0xd7ce, 0x0030, 0x0017, 0x3700, 0x4024, 0x0000, 0x0200, 0xb102, + 0x0024, 0x0000, 0x00c0, 0x2801, 0x0dc5, 0x0005, 0x4f92, 0x2909, 0xf840, + 0x3613, 0x2800, 0x0006, 0x0197, 0x0006, 0xa115, 0xb080, 0x0024, 0x3f00, + 0x3400, 0x0000, 0x190d, 0x000a, 0x708f, 0x280a, 0xc0c0, 0x0000, 0xd7ce, + 0x0000, 0x004d, 0x0020, 0xfe0f, 0x2820, 0xfb40, 0x0001, 0x0fce, 0x2801, + 0x1195, 0x3009, 0x1000, 0x6012, 0x93cc, 0x0000, 0x0024, 0x2801, 0x2c45, + 0x0000, 0x0024, 0x3413, 0x0024, 0x34b0, 0x0024, 0x4080, 0x0024, 0x0000, + 0x0200, 0x2801, 0x1495, 0xb882, 0x0024, 0x3453, 0x0024, 0x3009, 0x13c0, + 0x4080, 0x0024, 0x0000, 0x0200, 0x2801, 0x2c45, 0x0000, 0x0024, 0xb882, + 0x130c, 0x0000, 0x004d, 0x0021, 0x058f, 0x2821, 0x0340, 0x0001, 0x158e, + 0x2801, 0x25d5, 0x6012, 0x0024, 0x0000, 0x0024, 0x2801, 0x25d5, 0x0000, + 0x0024, 0x34c3, 0x184c, 0x3e13, 0xb80f, 0xf400, 0x4500, 0x0026, 0x9dcf, + 0x0001, 0x198e, 0x0000, 0xfa0d, 0x2926, 0x8e80, 0x3e10, 0x110c, 0x36f3, + 0x0024, 0x2801, 0x25c0, 0x36f3, 0x980f, 0x001c, 0xdd00, 0x001c, 0xd901, + 0x6ec2, 0x0024, 0x001c, 0xdd00, 0x2801, 0x1c95, 0x0018, 0xdbc1, 0x3413, + 0x184c, 0xf400, 0x4500, 0x2926, 0xc640, 0x3e00, 0x13cc, 0x2801, 0x2380, + 0x36f3, 0x0024, 0x6ec2, 0x0024, 0x003f, 0xc000, 0x2801, 0x1f15, 0x002a, + 0x4001, 0x3413, 0x184c, 0xf400, 0x4500, 0x2926, 0xafc0, 0x3e00, 0x13cc, + 0x2801, 0x2380, 0x36f3, 0x0024, 0xb400, 0x0024, 0xd100, 0x0024, 0x0000, + 0x0024, 0x2801, 0x2385, 0x0000, 0x0024, 0x3613, 0x0024, 0x3e11, 0x4024, + 0x2926, 0x8540, 0x3e01, 0x0024, 0x4080, 0x1b8c, 0x0000, 0x0024, 0x2801, + 0x2385, 0x0000, 0x0024, 0x3413, 0x184c, 0xf400, 0x4500, 0x2926, 0x8e80, + 0x3e10, 0x13cc, 0x36f3, 0x0024, 0x3110, 0x8024, 0x31f0, 0xc024, 0x0000, + 0x4000, 0x0000, 0x0021, 0x6d06, 0x0024, 0x3110, 0x8024, 0x2826, 0xa8c4, + 0x31f0, 0xc024, 0x2a26, 0xad00, 0x34c3, 0x184c, 0x3410, 0x8024, 0x3430, + 0xc024, 0x0000, 0x4000, 0x0000, 0x0021, 0x6d06, 0x0024, 0x0000, 0x0024, + 0x2801, 0x2c54, 0x4d06, 0x0024, 0x0000, 0x0200, 0x2922, 0x1885, 0x0001, + 0x2ac8, 0x0000, 0x0200, 0x3e10, 0x8024, 0x2921, 0xca80, 0x3e00, 0xc024, + 0x291a, 0x8a40, 0x0000, 0x0024, 0x2922, 0x1880, 0x36f3, 0x0024, 0x0000, + 0x004d, 0x0021, 0x0ecf, 0x2821, 0x0bc0, 0x0001, 0x2bce, 0x2801, 0x0ec0, + 0x3c30, 0x4024, 0x0000, 0x190d, 0x0001, 0x2d4e, 0x2821, 0x0f80, 0x0021, + 0x420f, 0x0000, 0x190d, 0x3e00, 0x0024, 0x2801, 0xca80, 0x0021, 0x42c8, + 0x0020, 0xcd4f, 0x2820, 0xc780, 0x0001, 0x2f0e, 0x0006, 0xf017, 0x0000, + 0x0015, 0xb070, 0xbc15, 0x0001, 0x30ce, 0x0020, 0xdf0f, 0x2820, 0xcd80, + 0x0000, 0x190d, 0x3e00, 0x23c1, 0x2801, 0xca80, 0x0020, 0xdfc8, 0x3613, + 0x0024, 0x3e10, 0xb803, 0x3e14, 0x3811, 0x3e11, 0x3805, 0x3e00, 0x3801, + 0x0007, 0xc390, 0x0006, 0xa011, 0x3010, 0x0444, 0x3050, 0x4405, 0x6458, + 0x0302, 0xff94, 0x4081, 0x0003, 0xffc5, 0x48b6, 0x0024, 0xff82, 0x0024, + 0x42b2, 0x0042, 0xb458, 0x0003, 0x4cd6, 0x9801, 0xf248, 0x1bc0, 0xb58a, + 0x0024, 0x6de6, 0x1804, 0x0006, 0x0010, 0x3810, 0x9bc5, 0x3800, 0xc024, + 0x36f4, 0x1811, 0x36f0, 0x9803, 0x283e, 0x2d80, 0x0fff, 0xffc3, 0x2801, + 0x4600, 0x0000, 0x0024, 0x3413, 0x0024, 0x2801, 0x3a05, 0xf400, 0x4517, + 0x2801, 0x3e00, 0x6894, 0x13cc, 0x37b0, 0x184c, 0x6090, 0x1d51, 0x0000, + 0x0910, 0x3f00, 0x060c, 0x3100, 0x4024, 0x6016, 0xb812, 0x000c, 0x8012, + 0x2801, 0x3c91, 0xb884, 0x0024, 0x6894, 0x3002, 0x0000, 0x028d, 0x003a, + 0x5e0f, 0x0001, 0x4e0e, 0x2939, 0xb0c0, 0x3e10, 0x93cc, 0x4084, 0x9bd2, + 0x4282, 0x0024, 0x0000, 0x0040, 0x2801, 0x4005, 0x4292, 0x130c, 0x3443, + 0x0024, 0x2801, 0x4145, 0x000c, 0x8390, 0x2a01, 0x44c0, 0x3444, 0x0024, + 0x3073, 0x0024, 0xc090, 0x014c, 0x2801, 0x44c0, 0x3800, 0x0024, 0x000c, + 0x4113, 0xb880, 0x2380, 0x3304, 0x4024, 0x3800, 0x05cc, 0xcc92, 0x05cc, + 0x3910, 0x0024, 0x3910, 0x4024, 0x000c, 0x8110, 0x3910, 0x0024, 0x39f0, + 0x4024, 0x3810, 0x0024, 0x38d0, 0x4024, 0x3810, 0x0024, 0x38f0, 0x4024, + 0x34c3, 0x0024, 0x3444, 0x0024, 0x3073, 0x0024, 0x3063, 0x0024, 0x3000, + 0x0024, 0x4080, 0x0024, 0x0000, 0x0024, 0x2839, 0x53d5, 0x4284, 0x0024, + 0x3613, 0x0024, 0x2801, 0x4805, 0x6898, 0xb804, 0x0000, 0x0084, 0x293b, + 0x1cc0, 0x3613, 0x0024, 0x000c, 0x8117, 0x3711, 0x0024, 0x37d1, 0x4024, + 0x4e8a, 0x0024, 0x0000, 0x0015, 0x2801, 0x4ac5, 0xce9a, 0x0024, 0x3f11, + 0x0024, 0x3f01, 0x4024, 0x000c, 0x8197, 0x408a, 0x9bc4, 0x3f15, 0x4024, + 0x2801, 0x4d05, 0x4284, 0x3c15, 0x6590, 0x0024, 0x0000, 0x0024, 0x2839, + 0x53d5, 0x4284, 0x0024, 0x0000, 0x0024, 0x2801, 0x38d8, 0x458a, 0x0024, + 0x2a39, 0x53c0, 0x003e, 0x2d4f, 0x283a, 0x5ed5, 0x0001, 0x318e, 0x000c, + 0x4653, 0x0000, 0x0246, 0xffac, 0x0c01, 0x48be, 0x0024, 0x4162, 0x4546, + 0x6642, 0x4055, 0x3501, 0x8024, 0x0000, 0x0087, 0x667c, 0x4057, 0x000c, + 0x41d5, 0x283a, 0x62d5, 0x3501, 0x8024, 0x667c, 0x1c47, 0x3701, 0x8024, + 0x283a, 0x62d5, 0xc67c, 0x0024, 0x0000, 0x0024, 0x283a, 0x62c5, 0x0000, + 0x0024, 0x2a3a, 0x5ec0, 0x3009, 0x3851, 0x3e14, 0xf812, 0x3e12, 0xb817, + 0x3e11, 0x8024, 0x0006, 0x0293, 0x3301, 0x8024, 0x468c, 0x3804, 0x0006, + 0xa057, 0x2801, 0x5a04, 0x0006, 0x0011, 0x469c, 0x0024, 0x3be1, 0x8024, + 0x2801, 0x5a15, 0x0006, 0xc392, 0x3311, 0x0024, 0x33f1, 0x2844, 0x3009, + 0x2bc4, 0x0030, 0x04d2, 0x3311, 0x0024, 0x3a11, 0x0024, 0x3201, 0x8024, + 0x003f, 0xfc04, 0xb64c, 0x0fc4, 0xc648, 0x0024, 0x3a01, 0x0024, 0x3111, + 0x1fd3, 0x6498, 0x07c6, 0x868c, 0x2444, 0x0023, 0xffd2, 0x3901, 0x8e06, + 0x0030, 0x0551, 0x3911, 0x8e06, 0x3961, 0x9c44, 0xf400, 0x44c6, 0xd46c, + 0x1bc4, 0x36f1, 0xbc13, 0x2801, 0x6395, 0x36f2, 0x9817, 0x002b, 0xffd2, + 0x3383, 0x188c, 0x3e01, 0x8c06, 0x0006, 0xa097, 0x3009, 0x1c12, 0x3213, + 0x0024, 0x468c, 0xbc12, 0x002b, 0xffd2, 0xf400, 0x4197, 0x2801, 0x6084, + 0x3713, 0x0024, 0x2801, 0x60c5, 0x37e3, 0x0024, 0x3009, 0x2c17, 0x3383, + 0x0024, 0x3009, 0x0c06, 0x468c, 0x4197, 0x0006, 0xa052, 0x2801, 0x62c4, + 0x3713, 0x2813, 0x2801, 0x6305, 0x37e3, 0x0024, 0x3009, 0x2c17, 0x36f1, + 0x8024, 0x36f2, 0x9817, 0x36f4, 0xd812, 0x2100, 0x0000, 0x3904, 0x5bd1, + 0x2a01, 0x53ce, 0x3e11, 0x7804, 0x0030, 0x0257, 0x3701, 0x0024, 0x0013, + 0x4d05, 0xd45b, 0xe0e1, 0x0007, 0xc795, 0x2801, 0x6b15, 0x0fff, 0xff45, + 0x3511, 0x184c, 0x4488, 0xb808, 0x0006, 0x8a97, 0x2801, 0x6ac5, 0x3009, + 0x1c40, 0x3511, 0x1fc1, 0x0000, 0x0020, 0xac52, 0x1405, 0x6ce2, 0x0024, + 0x0000, 0x0024, 0x2801, 0x6ac1, 0x68c2, 0x0024, 0x291a, 0x8a40, 0x3e10, + 0x0024, 0x2921, 0xca80, 0x3e00, 0x4024, 0x36f3, 0x0024, 0x3009, 0x1bc8, + 0x36f0, 0x1801, 0x3601, 0x5804, 0x3e13, 0x780f, 0x3e13, 0xb808, 0x0008, + 0x9b0f, 0x0001, 0x6dce, 0x2908, 0x9300, 0x0000, 0x004d, 0x36f3, 0x9808, + 0x2000, 0x0000, 0x36f3, 0x580f, 0x0007, 0x81d7, 0x3711, 0x8024, 0x3711, + 0xc024, 0x3700, 0x0024, 0x0000, 0x2001, 0xb012, 0x0024, 0x0034, 0x0000, + 0x2801, 0x7105, 0x0000, 0x01c1, 0x0030, 0x0117, 0x3f00, 0x0024, 0x0014, + 0xc000, 0x0000, 0x01c1, 0x4fce, 0x0024, 0xffea, 0x0024, 0x48b6, 0x0024, + 0x4384, 0x4097, 0xb886, 0x45c6, 0xfede, 0x0024, 0x4db6, 0x0024, 0x466c, + 0x0024, 0x0006, 0xc610, 0x8dd6, 0x8007, 0x0000, 0x00c6, 0xff6e, 0x0024, + 0x48b2, 0x0024, 0x0034, 0x2406, 0xffee, 0x0024, 0x2914, 0xaa80, 0x40b2, + 0x0024, 0xf1c6, 0x0024, 0xf1d6, 0x0024, 0x0000, 0x0201, 0x8d86, 0x0024, + 0x61de, 0x0024, 0x0006, 0xc612, 0x2801, 0x7781, 0x0006, 0xc713, 0x4c86, + 0x0024, 0x2912, 0x1180, 0x0006, 0xc351, 0x0006, 0x0210, 0x2912, 0x0d00, + 0x3810, 0x984c, 0xf200, 0x2043, 0x2808, 0xa000, 0x3800, 0x0024, 0x3e12, + 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3625, 0x0024, 0x0000, 0x800a, + 0x3e10, 0x3801, 0x3e10, 0xb803, 0x3e11, 0x3805, 0x3e11, 0xb807, 0x3e14, + 0x3811, 0x0006, 0xa090, 0x2912, 0x0d00, 0x3e14, 0xc024, 0x4088, 0x8000, + 0x4080, 0x0024, 0x0007, 0x90d1, 0x2801, 0x7f45, 0x0000, 0x0024, 0x0007, + 0x9051, 0x3100, 0x4024, 0x4100, 0x0024, 0x3900, 0x0024, 0x0007, 0x90d1, + 0x0004, 0x0000, 0x31f0, 0x4024, 0x6014, 0x0400, 0x0000, 0x0024, 0x2801, + 0x8391, 0x4080, 0x0024, 0x0000, 0x0000, 0x2801, 0x8305, 0x0000, 0x0024, + 0x0007, 0x9053, 0x3300, 0x0024, 0x4080, 0x0024, 0x0000, 0x0000, 0x2801, + 0x8398, 0x0000, 0x0024, 0x0007, 0x9051, 0x3900, 0x0024, 0x3200, 0x504c, + 0x6410, 0x0024, 0x3cf0, 0x0000, 0x4080, 0x0024, 0x0006, 0xc691, 0x2801, + 0x9c45, 0x3009, 0x0400, 0x0000, 0x1001, 0x0007, 0x9051, 0x3100, 0x0024, + 0x6012, 0x0024, 0x0006, 0xc6d0, 0x2801, 0x9089, 0x003f, 0xe000, 0x0006, + 0xc693, 0x3900, 0x0c00, 0x3009, 0x0001, 0x6014, 0x0024, 0x0007, 0x1ad0, + 0x2801, 0x9095, 0x3009, 0x0000, 0x4080, 0x0024, 0x0000, 0x0301, 0x2801, + 0x8a85, 0x4090, 0x0024, 0x0000, 0x0024, 0x2801, 0x8b95, 0x0000, 0x0024, + 0x3009, 0x0000, 0xc012, 0x0024, 0x2801, 0x9080, 0x3009, 0x2001, 0x3009, + 0x0000, 0x6012, 0x0024, 0x0000, 0x0341, 0x2801, 0x8d95, 0x0000, 0x0024, + 0x6190, 0x0024, 0x2801, 0x9080, 0x3009, 0x2000, 0x6012, 0x0024, 0x0000, + 0x0381, 0x2801, 0x8f55, 0x0000, 0x0024, 0x6190, 0x0024, 0x2801, 0x9080, + 0x3009, 0x2000, 0x6012, 0x0024, 0x0000, 0x00c0, 0x2801, 0x9095, 0x0000, + 0x0024, 0x3009, 0x2000, 0x0006, 0xa090, 0x3009, 0x0000, 0x4080, 0x0024, + 0x0000, 0x0081, 0x2801, 0x9555, 0x0007, 0x8c13, 0x3300, 0x104c, 0xb010, + 0x0024, 0x0002, 0x8001, 0x2801, 0x97c5, 0x34f0, 0x0024, 0x2801, 0x9540, + 0x0000, 0x0024, 0x0006, 0xc351, 0x3009, 0x0000, 0x6090, 0x0024, 0x3009, + 0x2000, 0x2900, 0x0b80, 0x3009, 0x0405, 0x0006, 0xc6d1, 0x0006, 0xc690, + 0x3009, 0x0000, 0x3009, 0x0401, 0x6014, 0x0024, 0x0006, 0xa093, 0x2801, + 0x93d1, 0xb880, 0x0024, 0x2801, 0xa500, 0x3009, 0x2c00, 0x4040, 0x0024, + 0x6012, 0x0024, 0x0006, 0xc6d0, 0x2801, 0xa518, 0x0000, 0x0024, 0x0006, + 0xc693, 0x3009, 0x0c00, 0x3009, 0x0001, 0x6014, 0x0024, 0x0006, 0xc350, + 0x2801, 0xa501, 0x0000, 0x0024, 0x6090, 0x0024, 0x3009, 0x2c00, 0x3009, + 0x0005, 0x2900, 0x0b80, 0x0001, 0xa508, 0x3009, 0x0400, 0x4080, 0x0024, + 0x0003, 0x8000, 0x2801, 0xa505, 0x0000, 0x0024, 0x6400, 0x0024, 0x0000, + 0x0081, 0x2801, 0xa509, 0x0000, 0x0024, 0x0007, 0x8c13, 0x3300, 0x0024, + 0xb010, 0x0024, 0x0006, 0xc650, 0x2801, 0xa515, 0x0000, 0x0024, 0x0001, + 0x0002, 0x3413, 0x0000, 0x3009, 0x0401, 0x4010, 0x8406, 0x0000, 0x0281, + 0xa010, 0x13c1, 0x4122, 0x0024, 0x0000, 0x03c2, 0x6122, 0x8002, 0x462c, + 0x0024, 0x469c, 0x0024, 0xfee2, 0x0024, 0x48be, 0x0024, 0x6066, 0x8400, + 0x0006, 0xc350, 0x2801, 0xa501, 0x0000, 0x0024, 0x4090, 0x0024, 0x3009, + 0x2400, 0x2900, 0x0b80, 0x3009, 0x0005, 0x0007, 0x1b50, 0x2912, 0x0d00, + 0x3613, 0x0024, 0x3a00, 0x0380, 0x4080, 0x0024, 0x0000, 0x00c1, 0x2801, + 0xadc5, 0x3009, 0x0000, 0xb010, 0x008c, 0x4192, 0x0024, 0x6012, 0x0024, + 0x0006, 0xf051, 0x2801, 0xabd8, 0x3009, 0x0400, 0x0007, 0x1fd1, 0x30e3, + 0x0400, 0x4080, 0x0024, 0x0000, 0x0301, 0x2801, 0xadc5, 0x3009, 0x0000, + 0xb010, 0x0024, 0x0000, 0x0101, 0x6012, 0x0024, 0x0006, 0xf051, 0x2801, + 0xadd5, 0x0000, 0x0024, 0x3023, 0x0400, 0xf200, 0x184c, 0xb880, 0xa400, + 0x3009, 0x2000, 0x3009, 0x0441, 0x3e10, 0x4402, 0x2909, 0xa9c0, 0x3e10, + 0x8024, 0x36e3, 0x0024, 0x36f4, 0xc024, 0x36f4, 0x1811, 0x36f1, 0x9807, + 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f0, 0x1801, 0x3405, 0x9014, 0x36f3, + 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, 0x0024, + 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3615, 0x0024, 0x0000, + 0x800a, 0x3e10, 0x3801, 0x3e10, 0xb803, 0x3e11, 0x3805, 0x3e11, 0xf810, + 0x0001, 0x0010, 0x3e14, 0x7812, 0xb882, 0x3813, 0x2914, 0xbec0, 0x0000, + 0x2200, 0xb886, 0x12cc, 0x2801, 0xba40, 0x3454, 0x8024, 0x0001, 0x0000, + 0x3000, 0x984c, 0x4234, 0xb843, 0xf400, 0x4095, 0x003b, 0xffc2, 0x3500, + 0x4024, 0xb122, 0x0842, 0x4010, 0x0bc3, 0x4010, 0x0024, 0x4010, 0x0024, + 0x4010, 0x0024, 0x4d82, 0x4011, 0x2938, 0x0600, 0xf400, 0x4450, 0x3223, + 0x184c, 0x3210, 0x8024, 0x32d0, 0xc024, 0x2938, 0x0600, 0x4d82, 0x4450, + 0x3243, 0x1bc3, 0x6396, 0x0024, 0x0005, 0xdf90, 0x3000, 0x0024, 0x6302, + 0x0024, 0x0005, 0xe110, 0x2801, 0xb511, 0x0000, 0x0024, 0x2801, 0xc0c0, + 0x4086, 0x0024, 0x3200, 0x930c, 0x6398, 0x1111, 0x4244, 0x0844, 0xf400, + 0x4095, 0x3500, 0x584c, 0x4438, 0x0805, 0x453a, 0x4115, 0x3500, 0x8024, + 0x6122, 0x4155, 0x4280, 0x1404, 0x0001, 0x0002, 0x4244, 0x0024, 0x4244, + 0x0024, 0x4244, 0x0024, 0x4244, 0x0024, 0x2938, 0x2f80, 0xf400, 0x4090, + 0x6396, 0x0024, 0x0005, 0xdf50, 0x3000, 0x0024, 0x6302, 0x0024, 0x0005, + 0xe0d2, 0x2801, 0xbc51, 0x0000, 0x0381, 0x3073, 0x0024, 0x3023, 0x0024, + 0x3000, 0x0024, 0x6012, 0x0024, 0x0001, 0x2212, 0x2801, 0xc5d5, 0x0005, + 0x1453, 0x0001, 0x0011, 0x3093, 0x184c, 0x3000, 0x4024, 0x2900, 0x7680, + 0x3e00, 0x4024, 0x2801, 0xc7c0, 0x36f3, 0x0024, 0x0001, 0x0011, 0x0005, + 0xe3c1, 0x3613, 0x024c, 0x3e10, 0x4024, 0x3000, 0x8024, 0x2900, 0x5a00, + 0x3e00, 0x8024, 0x36e3, 0x0024, 0x36f4, 0xc024, 0x36f4, 0x5812, 0x36f1, + 0xd810, 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f0, 0x1801, 0x3405, 0x9014, + 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, + 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3625, 0x0024, + 0x0000, 0x800a, 0x3e10, 0x3801, 0x0000, 0x00c1, 0xb880, 0xb803, 0x3e10, + 0x904c, 0x3e11, 0x3806, 0x3e11, 0xf810, 0x0006, 0xf450, 0x3e14, 0x7812, + 0x3e14, 0xc024, 0x3cf0, 0x2080, 0x3009, 0x23c0, 0x3009, 0x2380, 0x0000, + 0x0640, 0x3009, 0x2000, 0x2921, 0x9440, 0x0000, 0x00c0, 0x2921, 0xdd40, + 0x3613, 0x0024, 0xf400, 0x4004, 0x0000, 0x01c0, 0x6400, 0x0024, 0x0000, + 0x00c0, 0x2801, 0xeac5, 0x0000, 0x01c1, 0x6412, 0x4100, 0x0006, 0x0581, + 0x2801, 0xe041, 0x4412, 0x0024, 0xf400, 0x4057, 0x3702, 0x0024, 0x2000, + 0x0000, 0x0000, 0x0024, 0x0000, 0x0641, 0x0006, 0xf410, 0x3613, 0x0000, + 0x6012, 0x0024, 0x0000, 0x0024, 0x2801, 0xd615, 0x0000, 0x0024, 0x3009, + 0x2004, 0x2900, 0xb3c0, 0x3e01, 0x0024, 0x2801, 0xe040, 0x36f3, 0x0024, + 0x0000, 0x0641, 0x0006, 0xf410, 0x3613, 0x0000, 0x6012, 0x0024, 0x0000, + 0x0024, 0x2801, 0xd915, 0x0000, 0x0024, 0x3009, 0x2004, 0x2900, 0xa1c0, + 0x3e01, 0x0024, 0x2801, 0xe040, 0x36f3, 0x0024, 0x0006, 0xf450, 0x3613, + 0x0000, 0x6090, 0x3804, 0x2900, 0xb3c0, 0x3009, 0x2000, 0x2801, 0xe040, + 0x36f3, 0x0024, 0x2923, 0x4f00, 0x0007, 0x2050, 0x2801, 0xe040, 0x3009, + 0x2000, 0x2923, 0x7580, 0x0001, 0xe048, 0x34d3, 0x184c, 0x3430, 0x0024, + 0x2922, 0x4fc0, 0x3e00, 0x0024, 0x2801, 0xe040, 0x36f3, 0x0024, 0x0007, + 0x2050, 0x0000, 0x3fc0, 0x3613, 0x0024, 0x2923, 0x8480, 0x3e00, 0x0024, + 0x36f3, 0x2000, 0x0000, 0x1800, 0x3413, 0x0024, 0xf400, 0x4510, 0x34f0, + 0x4024, 0x6192, 0x0024, 0x6014, 0x2001, 0x0007, 0x2051, 0x2801, 0xe2c1, + 0x0000, 0x0280, 0x3009, 0x2400, 0x3009, 0x0400, 0x4080, 0x0024, 0x0006, + 0xf352, 0x2801, 0xebd5, 0x3009, 0x0842, 0x3009, 0x0bc3, 0x4d86, 0x0024, + 0x0000, 0x0201, 0x2801, 0xe705, 0x0030, 0x0013, 0x0006, 0x8a93, 0x3009, + 0x0c40, 0x3009, 0x0fc1, 0x6cde, 0x0024, 0x0000, 0x0201, 0x2801, 0xebc1, + 0x0030, 0x0013, 0x3300, 0x0024, 0xb010, 0x0024, 0x0000, 0x0100, 0x2801, + 0xebd5, 0x0000, 0x00c1, 0x2921, 0x9440, 0x3613, 0x0024, 0x2921, 0xdd40, + 0x3613, 0x0024, 0xf400, 0x4004, 0x0000, 0x01c0, 0x6400, 0x0024, 0x0000, + 0x01c1, 0x2801, 0xd215, 0x0000, 0x00c0, 0x2921, 0x9440, 0x3613, 0x0024, + 0x2921, 0xc300, 0x0000, 0x0024, 0x36f4, 0xc024, 0x36f4, 0x5812, 0x36f1, + 0xd810, 0x36f1, 0x1806, 0x36f0, 0x9803, 0x36f0, 0x1801, 0x3405, 0x9014, + 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, + 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3615, 0x0024, + 0x0000, 0x800a, 0x3e10, 0x7802, 0x3e10, 0xf804, 0x3e11, 0x7810, 0x3e14, + 0x7812, 0x3e14, 0xc024, 0x2922, 0x1880, 0x0000, 0x0180, 0x2921, 0xdd40, + 0x6892, 0x184c, 0x4080, 0x0024, 0x0000, 0x0024, 0x2801, 0xf3c5, 0x0000, + 0x0024, 0x2802, 0x2f40, 0xb880, 0x0024, 0x2921, 0xdd40, 0x6892, 0x184c, + 0x4080, 0x0024, 0x0000, 0x0181, 0x2801, 0xf5d5, 0x0000, 0x0024, 0x2802, + 0x2f40, 0xb880, 0x0024, 0x2921, 0xdd40, 0x3613, 0x0024, 0x4080, 0x0024, + 0x0000, 0x0101, 0x2801, 0xf7c5, 0x0000, 0x0024, 0x2802, 0x2f40, 0xb880, + 0x0024, 0x2921, 0xdd40, 0x3613, 0x0024, 0x4080, 0x0024, 0x0000, 0x00c1, + 0x2801, 0xf9c5, 0x0000, 0x0024, 0x2802, 0x2f40, 0xb880, 0x0024, 0x2921, + 0xdd40, 0x3613, 0x0024, 0x4080, 0x0024, 0x0000, 0x0141, 0x2801, 0xfbc5, + 0x0006, 0xf250, 0x2802, 0x2f40, 0xb880, 0x0024, 0x2921, 0xdd40, 0x3613, + 0x0024, 0x0000, 0x0101, 0x2921, 0xdd40, 0x3613, 0x2000, 0x0000, 0x03c1, + 0x6012, 0x03cc, 0x3613, 0x2000, 0x2802, 0x0115, 0x0006, 0xf051, 0x3009, + 0x3841, 0x2921, 0xdd40, 0x0000, 0x0201, 0xb080, 0x024c, 0x3009, 0x2000, + 0x2921, 0xdd40, 0x0000, 0x0401, 0x3009, 0x0401, 0xc100, 0x0024, 0x2802, + 0x0240, 0x3009, 0x2400, 0x3009, 0x0002, 0x2920, 0x5d00, 0x3e00, 0x8024, + 0x36f3, 0x024c, 0x3009, 0x2000, 0x0000, 0x0101, 0x2921, 0xdd40, 0x3613, + 0x0024, 0x0000, 0x0141, 0x3013, 0x0024, 0x3009, 0x21c0, 0x3009, 0x0000, + 0x6012, 0x0024, 0x0007, 0x1b51, 0x2802, 0x1395, 0x0000, 0x0101, 0x0007, + 0xc251, 0x2921, 0xdd40, 0x3613, 0x0024, 0x0000, 0x03c1, 0x6012, 0x2400, + 0x3100, 0x984c, 0x2802, 0x0ad5, 0x0007, 0xc292, 0x3009, 0x3841, 0x2921, + 0xdd40, 0x0000, 0x0201, 0x4082, 0x044c, 0xb080, 0x0024, 0x3910, 0x0024, + 0x39f0, 0x7841, 0x2921, 0xdd40, 0x0000, 0x0401, 0x3211, 0x1bcc, 0xb182, + 0x0bc5, 0xcec2, 0x0024, 0x3a10, 0x0024, 0x2802, 0x0c00, 0x3af0, 0x4024, + 0x2920, 0x5d00, 0x3e00, 0x8024, 0x36f3, 0x044c, 0x3910, 0x0024, 0x39f0, + 0x4024, 0x0007, 0x1b52, 0x0000, 0x0141, 0x2921, 0xdd40, 0x3613, 0x0024, + 0x3111, 0x2240, 0xb880, 0x03cc, 0x31f1, 0x6800, 0xb182, 0x8000, 0x6ce6, + 0x0024, 0x002e, 0xe002, 0x2802, 0x1a85, 0xb886, 0x0024, 0x6de2, 0x0b8c, + 0x0000, 0x00c1, 0x2802, 0x1251, 0x3009, 0x0800, 0xb010, 0x0024, 0x4192, + 0x0024, 0x6012, 0x0024, 0x0007, 0x1b52, 0x2802, 0x1258, 0x0000, 0x0024, + 0x6890, 0xa004, 0x2802, 0x1a80, 0x3009, 0x2800, 0x4e82, 0x0024, 0x0000, + 0x0020, 0xf2c2, 0x0024, 0x2802, 0x1a80, 0x3009, 0x2000, 0x3009, 0x07c0, + 0x4080, 0x0024, 0x0000, 0x0024, 0x2802, 0x1a85, 0x0000, 0x0024, 0x3093, + 0x0400, 0x4080, 0x03cc, 0x0017, 0x7001, 0x2802, 0x1995, 0x3009, 0x0000, + 0x6012, 0x0024, 0x0007, 0x1b50, 0x2802, 0x1901, 0xb880, 0x0024, 0x0000, + 0x00c1, 0x31f3, 0x0024, 0x3009, 0x0400, 0xb010, 0x0024, 0x4080, 0x0024, + 0x0000, 0x0000, 0x2802, 0x1989, 0x0000, 0x0024, 0x2802, 0x1a80, 0x3009, + 0x2000, 0x0006, 0xf050, 0x3009, 0x0000, 0x4000, 0x0024, 0x3009, 0x2000, + 0x0000, 0x0081, 0x0006, 0xf250, 0x3009, 0x0000, 0x6012, 0x0024, 0x0007, + 0xc151, 0x2802, 0x1cc5, 0x0000, 0x0024, 0x2802, 0x2f40, 0xb880, 0x0024, + 0x2921, 0xdd40, 0x6892, 0x184c, 0x6892, 0x2400, 0x2921, 0xdd40, 0x3009, + 0x184c, 0x4080, 0x0024, 0x0000, 0x0381, 0x2802, 0x1f85, 0x0000, 0x0024, + 0x2921, 0xdd40, 0x3613, 0x0024, 0x2921, 0xdd40, 0x6892, 0x184c, 0x4080, + 0x0024, 0x0000, 0x0240, 0x2802, 0x2205, 0x0000, 0x00c1, 0x2921, 0xdd40, + 0x6892, 0x184c, 0x0000, 0x00c1, 0x0000, 0x0240, 0x0006, 0x0752, 0x2922, + 0x1880, 0x3613, 0x0024, 0x2921, 0xdd40, 0x3613, 0x0024, 0x4080, 0x2800, + 0x0000, 0x0201, 0x2802, 0x2515, 0x3613, 0x0024, 0x2921, 0xdd40, 0x0002, + 0x2788, 0x3613, 0x0024, 0x4090, 0x1bcc, 0x0000, 0x0241, 0x2802, 0x2715, + 0x0006, 0x07d3, 0x2921, 0xdd40, 0x3613, 0x0024, 0x2802, 0x2780, 0x3b00, + 0x0024, 0x2802, 0x2f40, 0xb880, 0x0024, 0x0006, 0x0813, 0xb880, 0x184c, + 0x2921, 0xdd40, 0x6892, 0x2c00, 0x4080, 0x0024, 0x0006, 0x0810, 0x2802, + 0x2d05, 0x0000, 0x4003, 0x3000, 0x184c, 0xff86, 0x0024, 0x48b6, 0x0024, + 0x2921, 0xdd40, 0x6892, 0x2002, 0x0000, 0x0201, 0x2921, 0xdd40, 0x4088, + 0x184c, 0x3000, 0x4024, 0x4100, 0x0024, 0x4488, 0x2000, 0x0000, 0x4003, + 0x2802, 0x2995, 0x0006, 0x0810, 0x2921, 0xdd40, 0x6892, 0x184c, 0x4080, + 0x0024, 0x0000, 0x0201, 0x2802, 0x2f05, 0x0000, 0x0024, 0x2921, 0xdd40, + 0x3613, 0x0024, 0x6890, 0x0024, 0x36f4, 0xc024, 0x36f4, 0x5812, 0x36f1, + 0x5810, 0x36f0, 0xd804, 0x36f0, 0x5802, 0x3405, 0x9014, 0x36f3, 0x0024, + 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, 0x0024, 0x3e12, + 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3635, 0x0024, 0x0000, 0x800a, + 0x3e10, 0x3801, 0x0000, 0x0081, 0x3e10, 0xb803, 0x3e11, 0x3805, 0x3e11, + 0xb807, 0x3e14, 0x3811, 0x0006, 0xf250, 0x3e04, 0xb813, 0x3009, 0x0000, + 0x6012, 0x0024, 0x003f, 0xff01, 0x2802, 0x3a05, 0x0006, 0x07d1, 0x6194, + 0x0400, 0x0000, 0x0041, 0xa020, 0x984c, 0x0000, 0x01c2, 0xfe02, 0x0024, + 0x48b2, 0x0024, 0x3e10, 0x0024, 0x2921, 0xca80, 0x3e00, 0x4024, 0x3100, + 0x5bcc, 0x2921, 0xdd40, 0xb122, 0x0024, 0x291a, 0x8a40, 0x0002, 0x4c08, + 0x0007, 0x2052, 0x0006, 0x8a93, 0x3100, 0x184c, 0xa010, 0x0024, 0x0000, + 0x0041, 0x6090, 0x0024, 0x2922, 0x1880, 0x6090, 0x0024, 0xb880, 0x010c, + 0x3100, 0x2800, 0xfe02, 0x8c44, 0x3613, 0x0fc5, 0x4eb2, 0x0024, 0x3009, + 0x2040, 0x0000, 0x00c0, 0x2921, 0xbb80, 0x3e00, 0x23c1, 0x0000, 0x01c1, + 0x6012, 0x0024, 0x0003, 0xf680, 0x2802, 0x4055, 0x0000, 0x0024, 0x36f3, + 0x0024, 0x291a, 0x8a40, 0x0002, 0x4c08, 0x2901, 0xca80, 0x3e00, 0x0024, + 0x3413, 0x0040, 0x36f3, 0x03c1, 0x3009, 0x0c44, 0x3009, 0x0fc5, 0x6ce2, + 0x0024, 0x3c10, 0x0024, 0xbc82, 0x33c1, 0x3410, 0x2040, 0x34e0, 0x63c1, + 0x4c82, 0x0024, 0x0000, 0x0024, 0x2802, 0x4909, 0x4c82, 0x0024, 0x0000, + 0x01c4, 0x4c86, 0x184c, 0x003f, 0xff40, 0xad06, 0x0024, 0x3e10, 0x8024, + 0x2921, 0xca80, 0x3e00, 0xc024, 0x36f3, 0x0024, 0x2921, 0x9440, 0x0000, + 0x0080, 0xb88a, 0x104c, 0x3410, 0x0c46, 0x34e0, 0x4fc7, 0xbce2, 0x984c, + 0x4cf2, 0x0024, 0x3e10, 0x0024, 0x2921, 0x9780, 0x3e00, 0x4024, 0x2802, + 0x4b00, 0x36e3, 0x0024, 0x0000, 0x0024, 0x2802, 0x4b18, 0x0000, 0x0024, + 0x4ce6, 0x184c, 0x3e10, 0x8024, 0x2921, 0x9780, 0x3e00, 0xc024, 0x36e3, + 0x0024, 0x291a, 0x8a40, 0x0000, 0x0100, 0x2922, 0x1880, 0x3613, 0x0024, + 0x36f4, 0x9813, 0x36f4, 0x1811, 0x36f1, 0x9807, 0x36f1, 0x1805, 0x36f0, + 0x9803, 0x36f0, 0x1801, 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, + 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, + 0x3815, 0x3e05, 0xb814, 0x3635, 0x0024, 0x0000, 0x800a, 0x3e10, 0x7802, + 0x3e10, 0xf804, 0x3e14, 0x3811, 0x0006, 0x8a91, 0x0006, 0x0790, 0x3e14, + 0xb813, 0x0007, 0x8b52, 0x3e13, 0xf80e, 0x3e03, 0x504c, 0xb880, 0x0024, + 0x3c00, 0x33c0, 0x2921, 0xb380, 0x3800, 0x0024, 0x2920, 0x6a00, 0x0030, + 0x0253, 0x0000, 0x0400, 0xb882, 0xa440, 0xb880, 0xa7c1, 0x3a00, 0x0024, + 0x0013, 0x1040, 0x3b00, 0x0024, 0x0000, 0x0180, 0x2922, 0x1880, 0x3613, + 0x0024, 0x4f82, 0x0024, 0x003f, 0xf801, 0xb010, 0x0024, 0x0015, 0xb801, + 0x6012, 0x0024, 0x0007, 0x8a50, 0x2802, 0x73d5, 0x0000, 0x0201, 0x0006, + 0x8a90, 0x2921, 0xdd40, 0x3613, 0x0024, 0x003f, 0xfe00, 0x3613, 0x0042, + 0xb882, 0x83c3, 0xbdc2, 0x0024, 0x3009, 0x2040, 0x2921, 0xdd40, 0x6892, + 0xa3c1, 0x4080, 0x0024, 0x0000, 0x0024, 0x2802, 0x5e95, 0x0000, 0x0024, + 0x2901, 0xee80, 0x0006, 0x0791, 0x4080, 0x2400, 0x0006, 0xf052, 0x2802, + 0x5e85, 0x0000, 0x0024, 0x3613, 0x0841, 0x3e10, 0x4802, 0x2909, 0xa9c0, + 0x3e10, 0x8024, 0x36e3, 0x0024, 0x0006, 0x0791, 0x3100, 0x0024, 0x4080, + 0x0024, 0x0000, 0x0024, 0x2921, 0xc305, 0x0002, 0x6f48, 0x0006, 0x0752, + 0xb880, 0x104c, 0x3613, 0x33c0, 0x2922, 0x1880, 0x0000, 0x0100, 0x3200, + 0x0024, 0x4080, 0x0024, 0x0000, 0x0024, 0x2902, 0x31d5, 0x0002, 0x67c8, + 0x0006, 0x07d3, 0xb880, 0x0024, 0x0006, 0x07d0, 0x3b00, 0x0024, 0x0000, + 0x0201, 0x2921, 0xdd40, 0x3613, 0x0024, 0x0000, 0x00c1, 0x3423, 0x0024, + 0x3c00, 0x0024, 0xa010, 0x0001, 0x4100, 0x0024, 0x0000, 0x3fc1, 0x3800, + 0x0024, 0x34e0, 0x0024, 0x6012, 0x0024, 0x0006, 0x07d0, 0x2802, 0x6385, + 0x0000, 0x0024, 0x2902, 0x31c0, 0x0000, 0x0024, 0x0006, 0x0810, 0x3000, + 0x0024, 0x4080, 0x0024, 0x0000, 0x0024, 0x2802, 0x6ec5, 0x0000, 0x0024, + 0xf200, 0x184c, 0xf200, 0x0024, 0xf200, 0x0024, 0xb182, 0x3840, 0x2921, + 0xca80, 0x3e00, 0x4024, 0x0000, 0x01c1, 0x291a, 0x8a40, 0x36e3, 0x0024, + 0xb888, 0x4411, 0x3000, 0x0024, 0xb012, 0x0024, 0x6410, 0x2001, 0x0000, + 0x0024, 0x2802, 0x6ec1, 0x0000, 0x0024, 0x4192, 0x0024, 0x2402, 0x6e81, + 0x0000, 0x0024, 0x2921, 0xdd40, 0x6892, 0x184c, 0x6498, 0x0024, 0x2921, + 0xc300, 0x0000, 0x0024, 0x291a, 0x8a40, 0x3413, 0x0024, 0xf400, 0x4512, + 0x0030, 0x0010, 0x0000, 0x0201, 0x2900, 0x0c80, 0x34f3, 0x0024, 0x3000, + 0x0024, 0xb010, 0x0024, 0x0000, 0x0100, 0x2802, 0x8095, 0x0000, 0x0401, + 0x2922, 0x1880, 0x3613, 0x0024, 0x2921, 0xdd40, 0x3613, 0x0024, 0x2802, + 0x7ec0, 0xb78e, 0x4006, 0x3000, 0x0024, 0x4080, 0x0024, 0x0000, 0x0024, + 0x2802, 0x8089, 0xf292, 0x0024, 0x6012, 0x904c, 0x0006, 0x0791, 0x2802, + 0x7718, 0x3100, 0x0024, 0x3000, 0x0024, 0x4090, 0x0024, 0x3800, 0x0024, + 0x3100, 0x0024, 0x4080, 0x4512, 0x34f3, 0x184c, 0x2802, 0x79d5, 0x0007, + 0x0553, 0x36f3, 0x0800, 0x6090, 0x0024, 0x4080, 0xa800, 0x0000, 0x0024, + 0x2802, 0x8088, 0x0000, 0x0024, 0x3009, 0x184c, 0x0006, 0xf312, 0x4ffe, + 0xb841, 0x2921, 0xdd40, 0x6892, 0x41c7, 0xb182, 0x9bcc, 0x291a, 0x8a40, + 0xcfce, 0x0024, 0x0004, 0x0001, 0xb880, 0x010c, 0x6890, 0x2000, 0x0007, + 0x80d0, 0xb880, 0xa800, 0x3000, 0x2c00, 0x0007, 0x1ad0, 0xff82, 0x0024, + 0x48b2, 0x0024, 0xf400, 0x4040, 0x0000, 0x03c1, 0xb010, 0x0024, 0x3009, + 0x2000, 0x0000, 0x0201, 0x0030, 0x0010, 0x3000, 0x0024, 0xb010, 0x0024, + 0x0000, 0x0180, 0x2802, 0x55c5, 0x0000, 0x0024, 0x6890, 0x1bcd, 0x36f3, + 0xd80e, 0x36f4, 0x9813, 0x36f4, 0x1811, 0x36f0, 0xd804, 0x36f0, 0x5802, + 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, + 0x9817, 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, + 0x3615, 0x0024, 0x0000, 0x800a, 0x3e10, 0xb803, 0x0012, 0x5103, 0x3e11, + 0x3805, 0x3e11, 0xb807, 0x3e14, 0x380d, 0x0030, 0x0250, 0x3e13, 0xf80e, + 0xbe8b, 0x83e0, 0x290c, 0x4840, 0x3613, 0x0024, 0x290c, 0x4840, 0x4086, + 0x984c, 0x0000, 0x00ce, 0x2402, 0x8a8e, 0x3009, 0x1bc0, 0x0000, 0x01c3, + 0xae3a, 0x184c, 0x0000, 0x0043, 0x3009, 0x3842, 0x290c, 0x4840, 0x3009, + 0x3840, 0x4084, 0x9bc0, 0xfe26, 0x9bc2, 0xceba, 0x0024, 0x4e8e, 0x0024, + 0x4e9a, 0x0024, 0x4f8e, 0x0024, 0x0000, 0x0102, 0x2802, 0x8fc5, 0x0030, + 0x0010, 0x0000, 0x0206, 0x3613, 0x0024, 0x290c, 0x4840, 0x3009, 0x3840, + 0x3000, 0xdbc0, 0xb366, 0x0024, 0x0000, 0x0024, 0x2802, 0x8fd5, 0x4e8e, + 0x0024, 0x4e9a, 0x0024, 0x4f8e, 0x0024, 0x0030, 0x0010, 0x2802, 0x8c95, + 0x0000, 0x0206, 0x36f3, 0xd80e, 0x36f4, 0x180d, 0x36f1, 0x9807, 0x36f1, + 0x1805, 0x36f0, 0x9803, 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, + 0x2000, 0x0000, 0x36f2, 0x9817, 0x0007, 0x0001, /*copy 1*/ + 0x802e, 0x0006, 0x0002, /*copy 2*/ + 0x2801, 0x6480, 0x0007, 0x0001, /*copy 1*/ + 0x8030, 0x0006, 0x0002, /*copy 2*/ + 0x2800, 0x1b40, 0x0007, 0x0001, /*copy 1*/ + 0x8028, 0x0006, 0x0002, /*copy 2*/ + 0x2a00, 0x144e, 0x0007, 0x0001, /*copy 1*/ + 0x8032, 0x0006, 0x0002, /*copy 2*/ + 0x2801, 0x7980, 0x0007, 0x0001, /*copy 1*/ + 0x3580, 0x0006, 0x8038, 0x0000, /*Rle(56)*/ + 0x0007, 0x0001, /*copy 1*/ + 0xfab3, 0x0006, 0x01a4, /*copy 420*/ + 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, 0xffff, 0xfffe, 0xfffb, 0xfff9, + 0xfff5, 0xfff2, 0xffed, 0xffe8, 0xffe3, 0xffde, 0xffd8, 0xffd3, 0xffce, + 0xffca, 0xffc7, 0xffc4, 0xffc4, 0xffc5, 0xffc7, 0xffcc, 0xffd3, 0xffdc, + 0xffe6, 0xfff3, 0x0001, 0x0010, 0x001f, 0x002f, 0x003f, 0x004e, 0x005b, + 0x0066, 0x006f, 0x0074, 0x0075, 0x0072, 0x006b, 0x005f, 0x004f, 0x003c, + 0x0024, 0x0009, 0xffed, 0xffcf, 0xffb0, 0xff93, 0xff77, 0xff5f, 0xff4c, + 0xff3d, 0xff35, 0xff34, 0xff3b, 0xff4a, 0xff60, 0xff7e, 0xffa2, 0xffcd, + 0xfffc, 0x002e, 0x0061, 0x0094, 0x00c4, 0x00f0, 0x0114, 0x0131, 0x0144, + 0x014b, 0x0146, 0x0134, 0x0116, 0x00eb, 0x00b5, 0x0075, 0x002c, 0xffde, + 0xff8e, 0xff3d, 0xfeef, 0xfea8, 0xfe6a, 0xfe39, 0xfe16, 0xfe05, 0xfe06, + 0xfe1b, 0xfe43, 0xfe7f, 0xfecd, 0xff2a, 0xff95, 0x0009, 0x0082, 0x00fd, + 0x0173, 0x01e1, 0x0242, 0x0292, 0x02cc, 0x02ec, 0x02f2, 0x02da, 0x02a5, + 0x0253, 0x01e7, 0x0162, 0x00c9, 0x0021, 0xff70, 0xfebc, 0xfe0c, 0xfd68, + 0xfcd5, 0xfc5b, 0xfc00, 0xfbc9, 0xfbb8, 0xfbd2, 0xfc16, 0xfc85, 0xfd1b, + 0xfdd6, 0xfeae, 0xff9e, 0x009c, 0x01a0, 0x02a1, 0x0392, 0x046c, 0x0523, + 0x05b0, 0x060a, 0x062c, 0x0613, 0x05bb, 0x0526, 0x0456, 0x0351, 0x021f, + 0x00c9, 0xff5a, 0xfde1, 0xfc6a, 0xfb05, 0xf9c0, 0xf8aa, 0xf7d0, 0xf73d, + 0xf6fa, 0xf70f, 0xf77e, 0xf848, 0xf96b, 0xfadf, 0xfc9a, 0xfe8f, 0x00ad, + 0x02e3, 0x051a, 0x073f, 0x0939, 0x0af4, 0x0c5a, 0x0d59, 0x0de1, 0x0de5, + 0x0d5c, 0x0c44, 0x0a9e, 0x0870, 0x05c7, 0x02b4, 0xff4e, 0xfbaf, 0xf7f8, + 0xf449, 0xf0c7, 0xed98, 0xeae0, 0xe8c4, 0xe765, 0xe6e3, 0xe756, 0xe8d2, + 0xeb67, 0xef19, 0xf3e9, 0xf9cd, 0x00b5, 0x088a, 0x112b, 0x1a72, 0x2435, + 0x2e42, 0x3866, 0x426b, 0x4c1b, 0x553e, 0x5da2, 0x6516, 0x6b6f, 0x7087, + 0x7441, 0x7686, 0x774a, 0x7686, 0x7441, 0x7087, 0x6b6f, 0x6516, 0x5da2, + 0x553e, 0x4c1b, 0x426b, 0x3866, 0x2e42, 0x2435, 0x1a72, 0x112b, 0x088a, + 0x00b5, 0xf9cd, 0xf3e9, 0xef19, 0xeb67, 0xe8d2, 0xe756, 0xe6e3, 0xe765, + 0xe8c4, 0xeae0, 0xed98, 0xf0c7, 0xf449, 0xf7f8, 0xfbaf, 0xff4e, 0x02b4, + 0x05c7, 0x0870, 0x0a9e, 0x0c44, 0x0d5c, 0x0de5, 0x0de1, 0x0d59, 0x0c5a, + 0x0af4, 0x0939, 0x073f, 0x051a, 0x02e3, 0x00ad, 0xfe8f, 0xfc9a, 0xfadf, + 0xf96b, 0xf848, 0xf77e, 0xf70f, 0xf6fa, 0xf73d, 0xf7d0, 0xf8aa, 0xf9c0, + 0xfb05, 0xfc6a, 0xfde1, 0xff5a, 0x00c9, 0x021f, 0x0351, 0x0456, 0x0526, + 0x05bb, 0x0613, 0x062c, 0x060a, 0x05b0, 0x0523, 0x046c, 0x0392, 0x02a1, + 0x01a0, 0x009c, 0xff9e, 0xfeae, 0xfdd6, 0xfd1b, 0xfc85, 0xfc16, 0xfbd2, + 0xfbb8, 0xfbc9, 0xfc00, 0xfc5b, 0xfcd5, 0xfd68, 0xfe0c, 0xfebc, 0xff70, + 0x0021, 0x00c9, 0x0162, 0x01e7, 0x0253, 0x02a5, 0x02da, 0x02f2, 0x02ec, + 0x02cc, 0x0292, 0x0242, 0x01e1, 0x0173, 0x00fd, 0x0082, 0x0009, 0xff95, + 0xff2a, 0xfecd, 0xfe7f, 0xfe43, 0xfe1b, 0xfe06, 0xfe05, 0xfe16, 0xfe39, + 0xfe6a, 0xfea8, 0xfeef, 0xff3d, 0xff8e, 0xffde, 0x002c, 0x0075, 0x00b5, + 0x00eb, 0x0116, 0x0134, 0x0146, 0x014b, 0x0144, 0x0131, 0x0114, 0x00f0, + 0x00c4, 0x0094, 0x0061, 0x002e, 0xfffc, 0xffcd, 0xffa2, 0xff7e, 0xff60, + 0xff4a, 0xff3b, 0xff34, 0xff35, 0xff3d, 0xff4c, 0xff5f, 0xff77, 0xff93, + 0xffb0, 0xffcf, 0xffed, 0x0009, 0x0024, 0x003c, 0x004f, 0x005f, 0x006b, + 0x0072, 0x0075, 0x0074, 0x006f, 0x0066, 0x005b, 0x004e, 0x003f, 0x002f, + 0x001f, 0x0010, 0x0001, 0xfff3, 0xffe6, 0xffdc, 0xffd3, 0xffcc, 0xffc7, + 0xffc5, 0xffc4, 0xffc4, 0xffc7, 0xffca, 0xffce, 0xffd3, 0xffd8, 0xffde, + 0xffe3, 0xffe8, 0xffed, 0xfff2, 0xfff5, 0xfff9, 0xfffb, 0xfffe, 0xffff, + 0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, 0x0007, 0x0001, /*copy 1*/ + 0x180b, 0x0006, 0x0012, /*copy 18*/ + 0x000f, 0x0010, 0x001c, 0xfab3, 0x3580, 0x8037, 0xa037, 0x0001, 0x0000, + 0x3580, 0x01a4, 0x0750, 0x075c, 0x076f, 0x0768, 0x0773, 0x0775, 0x077b, + 0x000a, 0x0001, /*copy 1*/ + 0x0050, +#define PLUGIN_SIZE 5594 +#ifndef SKIP_PLUGIN_VARNAME +}; +#endif diff --git a/targets/esp32/components/VS1053/include/patches_pitch.h b/targets/esp32/components/VS1053/include/patches_pitch.h new file mode 100644 index 00000000..5c2effe7 --- /dev/null +++ b/targets/esp32/components/VS1053/include/patches_pitch.h @@ -0,0 +1,688 @@ + +#ifndef SKIP_PLUGIN_VARNAME +const unsigned short PLUGIN[] = { + /* Compressed plugin */ +#endif + 0x0007, 0x0001, /*copy 1*/ + 0x8050, 0x0006, 0x0020, /*copy 32*/ + 0x2a00, 0xc000, 0x2a02, 0x75c0, 0x3e12, 0xb817, 0x3e14, 0xf812, 0x3e01, + 0xb811, 0x0007, 0x9717, 0x0020, 0xffd2, 0x0030, 0x11d1, 0x3111, 0x8024, + 0x3704, 0xc024, 0x3b81, 0x8024, 0x3101, 0x8024, 0x3b81, 0x8024, 0x3f04, + 0xc024, 0x2808, 0x4800, 0x36f1, 0x9811, 0x0007, 0x0001, /*copy 1*/ + 0x8060, 0x0006, 0x0516, /*copy 1302*/ + 0xf400, 0x4095, 0x0000, 0x02c2, 0x6124, 0x0024, 0x0000, 0x0024, 0x2800, + 0x1ac5, 0x4192, 0x4542, 0x0000, 0x0041, 0x2000, 0x0015, 0x0030, 0x0317, + 0x2000, 0x0000, 0x3f00, 0x4024, 0x2000, 0x0000, 0x0000, 0x0000, 0x3e12, + 0x3800, 0x3e00, 0xb804, 0x0030, 0x0015, 0x0007, 0x8257, 0x3700, 0x984c, + 0xf224, 0x1444, 0xf224, 0x0024, 0x0008, 0x0002, 0x2910, 0x0181, 0x0000, + 0x1bc8, 0xb428, 0x1402, 0x0000, 0x8004, 0x2910, 0x0195, 0x0000, 0x1bc8, + 0xb428, 0x0024, 0x0006, 0x0095, 0x2800, 0x2945, 0x3e13, 0x780e, 0x3e11, + 0x7803, 0x3e13, 0xf806, 0x3e11, 0xf801, 0x3510, 0xb808, 0x003f, 0xe004, + 0xfec4, 0x3800, 0x48be, 0x17c3, 0xfec6, 0x41c2, 0x48be, 0x4497, 0x4090, + 0x1c46, 0xf06c, 0x0024, 0x2400, 0x2580, 0x6090, 0x41c3, 0x6628, 0x1c47, + 0x0000, 0x0024, 0x2800, 0x2449, 0xf07e, 0x0024, 0xf400, 0x4182, 0x673a, + 0x1c46, 0x0000, 0x0024, 0x2800, 0x2589, 0xf06c, 0x0024, 0xf400, 0x41c3, + 0x0000, 0x0024, 0x4224, 0x3442, 0x2902, 0xb7c0, 0x4336, 0x37c3, 0x0000, + 0x1805, 0x2902, 0xb7c0, 0x4508, 0x40c2, 0x450a, 0x9808, 0x0000, 0x0207, + 0xa478, 0x1bc0, 0xc45a, 0x1807, 0x0030, 0x03d5, 0x3d01, 0x5bc1, 0x36f3, + 0xd806, 0x3601, 0x5803, 0x36f3, 0x0024, 0x36f3, 0x580e, 0x0007, 0x8257, + 0x0000, 0x6004, 0x3730, 0x8024, 0xb244, 0x1c04, 0xd428, 0x3c02, 0x0006, + 0xc717, 0x2800, 0x2d05, 0x4284, 0x0024, 0x3613, 0x3c02, 0x0006, 0xc357, + 0x2901, 0x6b00, 0x3e11, 0x5c05, 0x4284, 0x1bc5, 0x0007, 0x8257, 0x2800, + 0x3285, 0x0002, 0x0001, 0x3701, 0x0024, 0x0006, 0xc357, 0xb412, 0x9c02, + 0x002e, 0xe001, 0x2800, 0x3005, 0x6212, 0x0024, 0x0000, 0x0024, 0x2800, + 0x3295, 0x0000, 0x0024, 0x0030, 0x0117, 0x3f00, 0x0024, 0x3613, 0x0024, + 0x3e10, 0x3813, 0x3e14, 0x8024, 0x3e04, 0x8024, 0x2900, 0x4b40, 0x0006, + 0x02d3, 0x36e3, 0x0024, 0x3009, 0x1bd3, 0x0007, 0x8257, 0x3700, 0x8024, + 0xf224, 0x0024, 0x0000, 0x0024, 0x2800, 0x3491, 0x3600, 0x9844, 0x2900, + 0x3a40, 0x0000, 0x3508, 0x2911, 0xf140, 0x0000, 0x0024, 0x0030, 0x0057, + 0x3700, 0x0024, 0xf200, 0x4595, 0x0fff, 0xfe02, 0xa024, 0x164c, 0x8000, + 0x17cc, 0x3f00, 0x0024, 0x3500, 0x0024, 0x0021, 0x6d82, 0xd024, 0x44c0, + 0x0006, 0xa402, 0x2800, 0x3955, 0xd024, 0x0024, 0x0000, 0x0000, 0x2800, + 0x3955, 0x000b, 0x6d57, 0x3009, 0x3c00, 0x36f0, 0x8024, 0x36f2, 0x1800, + 0x2000, 0x0000, 0x0000, 0x0024, 0x3e14, 0x7810, 0x3e13, 0xb80d, 0x3e13, + 0xf80a, 0x3e10, 0xb803, 0x3e11, 0x3805, 0x3e11, 0xb807, 0x3e14, 0xf801, + 0x3e15, 0x3815, 0x0001, 0x000a, 0x0006, 0xc4d7, 0xbf8e, 0x9c42, 0x3e01, + 0x9c03, 0x0006, 0xa017, 0x0023, 0xffd1, 0x0007, 0x8250, 0x0fff, 0xfd85, + 0x3001, 0x0024, 0xa45a, 0x4494, 0x0000, 0x0093, 0x2800, 0x4091, 0xf25a, + 0x104c, 0x34f3, 0x0024, 0x2800, 0x4091, 0x0000, 0x0024, 0x3413, 0x084c, + 0x0000, 0x0095, 0x3281, 0xf806, 0x4091, 0x4d64, 0x2400, 0x42c0, 0x4efa, + 0x9c10, 0xf1eb, 0x6061, 0xfe55, 0x2f66, 0x5653, 0x4d64, 0x48b2, 0xa201, + 0x4efa, 0xa201, 0x36f3, 0x3c10, 0x36f5, 0x1815, 0x36f4, 0xd801, 0x36f1, + 0x9807, 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f3, 0xd80a, 0x36f3, 0x980d, + 0x2000, 0x0000, 0x36f4, 0x5810, 0x36f3, 0x0024, 0x3009, 0x3848, 0x3e14, + 0x3811, 0x3e00, 0x0024, 0x0000, 0x4000, 0x0001, 0x0010, 0x2915, 0x94c0, + 0x0001, 0xcc11, 0x36f0, 0x0024, 0x2927, 0x9e40, 0x3604, 0x1811, 0x3613, + 0x0024, 0x3e14, 0x3811, 0x3e00, 0x0024, 0x0000, 0x4000, 0x0001, 0x0010, + 0x2915, 0x94c0, 0x0001, 0xcc11, 0x36f0, 0x0024, 0x36f4, 0x1811, 0x3009, + 0x1808, 0x2000, 0x0000, 0x0000, 0x190d, 0x3613, 0x0024, 0x3e22, 0xb815, + 0x3e05, 0xb814, 0x3615, 0x0024, 0x0000, 0x800a, 0x3e13, 0x7801, 0x3e10, + 0xb803, 0x3e11, 0x3805, 0x3e11, 0xb807, 0x3e14, 0x3811, 0x3e14, 0xb813, + 0x3e03, 0xf80e, 0xb488, 0x44d5, 0x3543, 0x134c, 0x34e5, 0xc024, 0x3524, + 0x8024, 0x35a4, 0xc024, 0x3710, 0x8a0c, 0x3540, 0x4a0c, 0x3d44, 0x8024, + 0x3a10, 0x8024, 0x3590, 0x0024, 0x4010, 0x15c1, 0x6010, 0x3400, 0x3710, + 0x8024, 0x2800, 0x5704, 0x3af0, 0x8024, 0x3df0, 0x0024, 0x3591, 0x4024, + 0x3530, 0x4024, 0x4192, 0x4050, 0x6100, 0x1482, 0x4020, 0x1753, 0xbf8e, + 0x1582, 0x4294, 0x4011, 0xbd86, 0x408e, 0x2400, 0x550e, 0xfe6d, 0x2819, + 0x520e, 0x0a00, 0x5207, 0x2819, 0x4fbe, 0x0024, 0xad56, 0x904c, 0xaf5e, + 0x1010, 0xf7d4, 0x0024, 0xf7fc, 0x2042, 0x6498, 0x2046, 0x3cf4, 0x0024, + 0x3400, 0x170c, 0x4090, 0x1492, 0x35a4, 0xc024, 0x2800, 0x4f95, 0x3c00, + 0x0024, 0x4480, 0x914c, 0x36f3, 0xd80e, 0x36f4, 0x9813, 0x36f4, 0x1811, + 0x36f1, 0x9807, 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f3, 0x5801, 0x3405, + 0x9014, 0x36e3, 0x0024, 0x2000, 0x0000, 0x36f2, 0x9815, 0x2814, 0x9c91, + 0x0000, 0x004d, 0x2814, 0x9940, 0x003f, 0x0013, 0x3613, 0x0024, 0x3e12, + 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3655, 0x0024, 0x0000, 0x800a, + 0x3e10, 0x3801, 0x3e10, 0xb803, 0x3e11, 0x3805, 0x3e11, 0xb810, 0x3e13, + 0xf80e, 0x3e03, 0x534c, 0x3450, 0x4024, 0x6814, 0x0024, 0x0000, 0x0024, + 0x2800, 0x7618, 0x4192, 0x0024, 0x2400, 0x75c1, 0x0000, 0x0024, 0xf400, + 0x4450, 0x2938, 0x1880, 0x3613, 0x0024, 0x3c10, 0x050c, 0x3c10, 0x4024, + 0x3c90, 0x8024, 0x34f3, 0x0024, 0x3464, 0x0024, 0x3011, 0x0c40, 0x3011, + 0x4c41, 0x2915, 0x9900, 0x3011, 0x8f82, 0x3411, 0x2c40, 0x3411, 0x6c41, + 0x2915, 0xa580, 0x34e1, 0xaf82, 0x3009, 0x3040, 0x4c8a, 0x0040, 0x3010, + 0x7041, 0x2800, 0x6854, 0x3010, 0xb382, 0x3411, 0x0024, 0x3411, 0x6c44, + 0x34e1, 0xac45, 0xbe8a, 0xaf86, 0x0fe0, 0x0006, 0x3009, 0x3044, 0x3009, + 0x3045, 0x3009, 0x3386, 0x3411, 0x0024, 0x3411, 0x4ccc, 0x2915, 0x9900, + 0x34e1, 0x984c, 0x3e10, 0x7800, 0x3009, 0x3802, 0x3011, 0x0c40, 0x3011, + 0x4c41, 0x2915, 0x9900, 0x30e1, 0x8f82, 0x3009, 0x1bc6, 0x2915, 0xa940, + 0x36f1, 0x5804, 0x3011, 0x2c40, 0x3011, 0x6c41, 0x30b1, 0xac42, 0x3009, + 0x0c40, 0x3009, 0x0c41, 0x2915, 0x9900, 0x3613, 0x0f82, 0x3e10, 0x7800, + 0x3009, 0x3802, 0x3010, 0x1044, 0x3010, 0x5045, 0x2915, 0x9900, 0x3010, + 0x9386, 0x3009, 0x1bc6, 0x2915, 0xa940, 0x36f1, 0x5804, 0xf1ca, 0xac40, + 0x4ce2, 0xac41, 0x3009, 0x2ec2, 0x2800, 0x7112, 0x629c, 0x0024, 0xf1c2, + 0x4182, 0x3c10, 0x0c44, 0x3c10, 0x4c45, 0x2915, 0x4780, 0x3ce0, 0x8f86, + 0x4080, 0x0024, 0x0000, 0x0024, 0x2800, 0x75d5, 0x0020, 0x0000, 0x3411, + 0x0c40, 0x3411, 0x4c41, 0x2915, 0xb780, 0x34e1, 0x8f82, 0x0000, 0x03c3, + 0x4234, 0x0024, 0x4c82, 0x0024, 0x0000, 0x0024, 0x2915, 0x4355, 0x0000, + 0x75c8, 0x0000, 0x0000, 0x3a10, 0x0d8c, 0x36f3, 0x538c, 0x36f3, 0xd80e, + 0x36f1, 0x9810, 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f0, 0x1801, 0x3405, + 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, + 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3645, + 0x0024, 0x0000, 0x800a, 0x3e10, 0x3801, 0x3e10, 0xb803, 0x3e11, 0x3805, + 0x3e11, 0xb810, 0x3e13, 0xf80e, 0x3e03, 0x534c, 0x3440, 0x4024, 0x4192, + 0x0024, 0x2400, 0x91c1, 0x0000, 0x0024, 0xb68c, 0x4450, 0x2938, 0x1880, + 0x3613, 0x050c, 0x3c10, 0x0c40, 0x3c10, 0x4c41, 0x3ce0, 0x8f82, 0x003c, + 0x2584, 0x2915, 0x9900, 0x0018, 0x8245, 0x3411, 0x2c40, 0x3411, 0x6c41, + 0x2915, 0xa580, 0x34e1, 0xac42, 0x4c8a, 0xb040, 0x3009, 0x3041, 0x2800, + 0x82d4, 0x3009, 0x3382, 0x3411, 0x0f4c, 0x3411, 0x6c44, 0x34e1, 0xac45, + 0xbe8a, 0xac46, 0x499c, 0xb044, 0xf38c, 0xb045, 0x3009, 0x3386, 0x3009, + 0x0c40, 0x3009, 0x0c41, 0xf1ca, 0x8f82, 0x4ce2, 0x1044, 0x3411, 0x4024, + 0x2800, 0x8512, 0x4294, 0x1386, 0x6294, 0x0024, 0xf1c2, 0x0024, 0x4e8a, + 0x4195, 0x35e3, 0x0024, 0x2915, 0xa955, 0xf400, 0x4546, 0x3009, 0x2c40, + 0x3009, 0x2c41, 0x3009, 0x2c42, 0x3009, 0x0c40, 0x3009, 0x0c41, 0xf1ca, + 0x8f82, 0x4ce2, 0x9044, 0x3009, 0x1045, 0x2800, 0x8985, 0x3009, 0x1386, + 0x2800, 0x8992, 0x4294, 0x0024, 0x6294, 0x0024, 0xf1c2, 0x0024, 0x4e8a, + 0x4195, 0x35e3, 0x0024, 0x2915, 0xa955, 0xf400, 0x4546, 0xf1ca, 0xac40, + 0x4ce2, 0xac41, 0x3009, 0x2ec2, 0x2800, 0x8c12, 0x629c, 0x0024, 0xf1c2, + 0x4182, 0x3c20, 0x0c84, 0x3cf0, 0x8fc6, 0x6264, 0x4017, 0x3cf0, 0x4fc5, + 0x2800, 0x91c8, 0x0020, 0x0000, 0x2800, 0x8f19, 0xf400, 0x45c0, 0x6cea, + 0x0024, 0x0000, 0x0024, 0x2800, 0x91c9, 0x0020, 0x0000, 0x3411, 0x0c40, + 0x3411, 0x4c41, 0x2915, 0xb780, 0x34e1, 0x8f82, 0x0000, 0x03c3, 0x4234, + 0x0024, 0x4c82, 0x0024, 0x0000, 0x0024, 0x2915, 0x4355, 0x0000, 0x91c8, + 0x0000, 0x0000, 0x3a10, 0x0d8c, 0x36f3, 0x53cc, 0x36f3, 0xd80e, 0x36f1, + 0x9810, 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f0, 0x1801, 0x3405, 0x9014, + 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0xf400, + 0x4595, 0x35e3, 0x3840, 0x3e13, 0xf80e, 0x3e13, 0x7808, 0x3510, 0x0024, + 0x3e10, 0x0024, 0x3510, 0x0024, 0x3e10, 0x0024, 0x3510, 0x0024, 0x3e00, + 0x0024, 0x0001, 0xce8e, 0x002b, 0xb30f, 0x292d, 0xa940, 0x0000, 0x004d, + 0x36d3, 0x0024, 0x36f3, 0x5808, 0x36f3, 0xd80e, 0x2000, 0x0000, 0x3009, + 0x1800, 0xf400, 0x4595, 0x35f3, 0x3840, 0x3e13, 0xf80e, 0x3e13, 0x7808, + 0x3510, 0x0024, 0x3e10, 0x0024, 0x3510, 0x0024, 0x3e00, 0x0024, 0x0000, + 0x9dce, 0x0028, 0x088f, 0x2927, 0xff80, 0x0000, 0x008d, 0x36e3, 0x0024, + 0x36f3, 0x5808, 0x36f3, 0xd80e, 0x2000, 0x0000, 0x3009, 0x1800, 0x0028, + 0x2b0f, 0x0000, 0xa34e, 0x2828, 0x0b15, 0x0007, 0x2605, 0x3613, 0x0001, + 0x3e14, 0x3811, 0x0001, 0x0011, 0x0001, 0xcc10, 0x2915, 0x94c0, 0x0000, + 0x4000, 0x3e10, 0x534c, 0x3430, 0xc024, 0x3e10, 0xc024, 0x2927, 0xc4c0, + 0x3e01, 0x0024, 0x36d3, 0x0024, 0x0001, 0x0011, 0x0001, 0xcc10, 0x2915, + 0x94c0, 0x0000, 0x4000, 0x2828, 0x0b00, 0x36f4, 0x1811, 0x3e00, 0x0024, + 0x2800, 0xa740, 0x0028, 0x2bc8, 0x3605, 0x7840, 0x3e13, 0x780e, 0x3e13, + 0xf808, 0x3e05, 0x4024, 0x0000, 0x458e, 0x0027, 0x9e0f, 0x2922, 0xa6c0, + 0x0000, 0x190d, 0x36f3, 0x0024, 0x36f3, 0xd808, 0x36f3, 0x580e, 0x2000, + 0x0000, 0x3009, 0x1800, 0xf400, 0x4595, 0x35d3, 0x3840, 0x3e13, 0xf80e, + 0x3e13, 0x7808, 0x3510, 0x0024, 0x3e10, 0x0024, 0x3510, 0x0024, 0x3e10, + 0x0024, 0x3510, 0x0024, 0x3e10, 0x0024, 0x3510, 0x0024, 0x3e00, 0x0024, + 0x0000, 0xac8e, 0x0025, 0xf54f, 0x2925, 0xe580, 0x0000, 0x004d, 0x36c3, + 0x0024, 0x36f3, 0x5808, 0x36f3, 0xd80e, 0x2000, 0x0000, 0x3009, 0x1800, + 0x3433, 0x0000, 0x6890, 0x3040, 0x3cc0, 0xa000, 0x0008, 0x6201, 0x000d, + 0x3500, 0x3613, 0x110c, 0x3e10, 0x0024, 0x3e10, 0x4024, 0x34c0, 0x8024, + 0x2900, 0x94c0, 0x3e00, 0x8024, 0x0026, 0x0a4f, 0x0000, 0xb04e, 0x2825, + 0xf880, 0x0000, 0x07cd, 0x0000, 0x0801, 0x6012, 0x0024, 0x0000, 0x0024, + 0x2826, 0x0a85, 0x0000, 0x0024, 0x2800, 0xad40, 0x0000, 0x0024, 0x3605, + 0x7840, 0x3e13, 0x780e, 0x3e13, 0xf808, 0x3e05, 0x4024, 0x0000, 0xb54e, + 0x0022, 0xf54f, 0x2922, 0xda80, 0x0000, 0x190d, 0x36f3, 0x0024, 0x36f3, + 0xd808, 0x36f3, 0x580e, 0x2000, 0x0000, 0x3009, 0x1800, 0x3e00, 0x0024, + 0x2800, 0x9980, 0x0022, 0xf608, 0x3605, 0x7840, 0x3e13, 0x780e, 0x3e13, + 0xf808, 0x3e05, 0x4024, 0x0000, 0xb94e, 0x0022, 0xa1cf, 0x2922, 0x9980, + 0x0000, 0x190d, 0x36f3, 0x0024, 0x36f3, 0xd808, 0x36f3, 0x580e, 0x2000, + 0x0000, 0x3009, 0x1800, 0x3009, 0x3400, 0x2800, 0xb200, 0x0022, 0xa288, + 0x2a01, 0x5a4e, 0x2a02, 0x7c0e, 0x2a02, 0x964e, 0x0007, 0x0001, /*copy 1*/ + 0x8300, 0x0006, 0x0ff6, /*copy 4086*/ + 0x0030, 0x0055, 0xb080, 0x1402, 0x0fdf, 0xffc1, 0x0007, 0x9257, 0xb212, + 0x3c00, 0x3d00, 0x4024, 0x0006, 0x0097, 0x3f10, 0x0024, 0x3f00, 0x0024, + 0x0030, 0x0297, 0x3f00, 0x0024, 0x0007, 0x9017, 0x3f00, 0x0024, 0x0007, + 0x81d7, 0x3f10, 0x0024, 0xc090, 0x3c00, 0x0006, 0x0297, 0xb080, 0x3c00, + 0x0000, 0x0401, 0x000a, 0x1055, 0x0006, 0x0017, 0x3f10, 0x3401, 0x000a, + 0x2795, 0x3f00, 0x3401, 0x0001, 0x6ad7, 0xf400, 0x55c0, 0x0000, 0x0817, + 0xb080, 0x57c0, 0x0014, 0x958f, 0x0000, 0x5b4e, 0x0030, 0x0017, 0x3700, + 0x0024, 0x0004, 0x0001, 0xb012, 0x0024, 0x0000, 0x004d, 0x280f, 0xe115, + 0x0006, 0x2016, 0x0006, 0x01d7, 0x3f00, 0x0024, 0x0000, 0x190d, 0x000f, + 0xf94f, 0x0000, 0xcd0e, 0x280f, 0xe100, 0x0006, 0x2016, 0x0000, 0x0080, + 0x0005, 0x4f92, 0x2909, 0xf840, 0x3613, 0x2800, 0x0006, 0x0197, 0x0006, + 0xa115, 0xb080, 0x0024, 0x3f00, 0x3400, 0x0007, 0x8a57, 0x3700, 0x0024, + 0x4080, 0x0024, 0x0000, 0x0040, 0x2800, 0xced5, 0x0006, 0xa2d7, 0x3009, + 0x3c00, 0x0006, 0xa157, 0x3009, 0x1c00, 0x0006, 0x01d7, 0x0000, 0x190d, + 0x000a, 0x708f, 0x0000, 0xd7ce, 0x290b, 0x1a80, 0x3f00, 0x184c, 0x0030, + 0x0017, 0x4080, 0x1c01, 0x0000, 0x0200, 0x2800, 0xcb15, 0xb102, 0x0024, + 0x0000, 0xcd08, 0x2800, 0xcb15, 0x0000, 0xd3ce, 0x0011, 0x210f, 0x0000, + 0x190d, 0x280f, 0xcb00, 0x3613, 0x0024, 0x0006, 0xa115, 0x0006, 0x01d7, + 0x37f0, 0x1401, 0x6100, 0x1c01, 0x4012, 0x0024, 0x0000, 0x8000, 0x6010, + 0x0024, 0x34f3, 0x0400, 0x2800, 0xd698, 0x0000, 0x0024, 0x0000, 0x8001, + 0x6010, 0x3c01, 0x0000, 0x000d, 0x2811, 0x8259, 0x0000, 0x0024, 0x2a11, + 0x2100, 0x0030, 0x0257, 0x3700, 0x0024, 0x4080, 0x0024, 0x0000, 0x0024, + 0x2800, 0xd9d5, 0x0006, 0x0197, 0x0006, 0xa115, 0x3f00, 0x3400, 0x003f, + 0xc000, 0xb600, 0x41c1, 0x0012, 0x5103, 0x000c, 0xc002, 0xdcd6, 0x0024, + 0x0019, 0xd4c2, 0x2802, 0x0c45, 0x0001, 0x1008, 0x0013, 0xd9c3, 0x6fd6, + 0x0024, 0x0000, 0x190d, 0x2800, 0xdf95, 0x0014, 0x1b01, 0x0020, 0x480f, + 0x0000, 0xde4e, 0x0000, 0x190d, 0x2820, 0x41c0, 0x0001, 0x1008, 0x0039, + 0x324f, 0x0001, 0x3ece, 0x2820, 0x4a18, 0xb882, 0x0024, 0x2a20, 0x48c0, + 0x003f, 0xfd00, 0xb700, 0x0024, 0x003f, 0xf901, 0x6010, 0x0024, 0x0000, + 0x0024, 0x280a, 0xc505, 0x0000, 0x190d, 0x0014, 0x1b01, 0x0015, 0x59c0, + 0x6fc2, 0x0024, 0x0000, 0x0024, 0x2800, 0xe9d5, 0x0000, 0x0024, 0x290c, + 0x4840, 0x3613, 0x0024, 0x290c, 0x4840, 0x4086, 0x184c, 0x0000, 0x18c2, + 0x6234, 0x0024, 0x0000, 0x1d02, 0x2800, 0xe5d5, 0x6234, 0x0024, 0x0030, + 0x0317, 0x2800, 0xe9c0, 0x3f00, 0x0024, 0x0000, 0x1d82, 0x2800, 0xe855, + 0x6234, 0x0024, 0x2912, 0x0d00, 0x4084, 0x184c, 0xf200, 0x0024, 0x6200, + 0x0024, 0x0006, 0x0017, 0x2800, 0xe540, 0xb080, 0x3c40, 0x0000, 0x0202, + 0x2800, 0xe9d5, 0xa024, 0x0024, 0xc020, 0x0024, 0x2800, 0xe540, 0x0030, + 0x02d7, 0x000a, 0x8c8f, 0x0000, 0xeb0e, 0x000c, 0x0981, 0x280a, 0x71c0, + 0x002c, 0x9d40, 0x000a, 0x708f, 0x0000, 0xd7ce, 0x280a, 0xc0d5, 0x0012, + 0x5182, 0x6fd6, 0x0024, 0x003f, 0xfd81, 0x280a, 0x8e45, 0xb710, 0x0024, + 0xb710, 0x0024, 0x003f, 0xfc01, 0x6012, 0x0024, 0x0000, 0x0101, 0x2801, + 0x06d5, 0xffd2, 0x0024, 0x48b2, 0x0024, 0x4190, 0x0024, 0x0000, 0x190d, + 0x2801, 0x06d5, 0x0030, 0x0250, 0xb880, 0x104c, 0x3cf0, 0x0024, 0x0010, + 0x5500, 0xb880, 0x23c0, 0xb882, 0x2000, 0x0007, 0x8590, 0x2914, 0xbec0, + 0x0000, 0x0440, 0x0007, 0x8b50, 0xb880, 0x0024, 0x2920, 0x0100, 0x3800, + 0x0024, 0x2920, 0x0000, 0x0006, 0x8a91, 0x0000, 0x0800, 0xb880, 0xa440, + 0x003f, 0xfd81, 0xb710, 0xa7c0, 0x003f, 0xfc01, 0x6012, 0x0024, 0x0000, + 0x0101, 0x2801, 0x1015, 0x0000, 0x0024, 0xffe2, 0x0024, 0x48b2, 0x0024, + 0x4190, 0x0024, 0x0000, 0x0024, 0x2801, 0x1015, 0x0000, 0x0024, 0x2912, + 0x2d80, 0x0000, 0x0780, 0x4080, 0x0024, 0x0006, 0x8a90, 0x2801, 0x1015, + 0x0000, 0x01c2, 0xb886, 0x8040, 0x3613, 0x03c1, 0xbcd2, 0x0024, 0x0030, + 0x0011, 0x2800, 0xfc95, 0x003f, 0xff42, 0xb886, 0x8040, 0x3009, 0x03c1, + 0x0000, 0x0020, 0xac22, 0x0024, 0x0000, 0x0102, 0x6cd2, 0x0024, 0x3e10, + 0x0024, 0x2909, 0x8c80, 0x3e00, 0x4024, 0x36f3, 0x0024, 0x3e11, 0x8024, + 0x3e01, 0xc024, 0x2901, 0x34c0, 0x0000, 0x0201, 0xf400, 0x4512, 0x2900, + 0x0c80, 0x3213, 0x1b8c, 0x3100, 0x0024, 0xb010, 0x0024, 0x0000, 0x0024, + 0x2801, 0x1015, 0x0000, 0x0024, 0x291a, 0x8a40, 0x0000, 0x0100, 0x2920, + 0x0200, 0x3633, 0x0024, 0x2920, 0x0280, 0x0000, 0x0401, 0x408e, 0x0024, + 0x2920, 0x0280, 0x0000, 0x0401, 0x003f, 0xfd81, 0xb710, 0x4006, 0x003f, + 0xfc01, 0x6012, 0x0024, 0x0000, 0x0101, 0x2801, 0x1015, 0x0000, 0x0024, + 0xffe2, 0x0024, 0x48b2, 0x0024, 0x4190, 0x0024, 0x0000, 0x0024, 0x2801, + 0x1015, 0x0000, 0x0024, 0x2912, 0x2d80, 0x0000, 0x0780, 0x4080, 0x0024, + 0x0000, 0x01c2, 0x2800, 0xf885, 0x0006, 0x8a90, 0x2a01, 0x1000, 0x2920, + 0x0100, 0x0000, 0x0401, 0x0000, 0x0180, 0x2920, 0x0200, 0x3613, 0x0024, + 0x2920, 0x0280, 0x3613, 0x0024, 0x0000, 0x0401, 0x2920, 0x0280, 0x4084, + 0x984c, 0x0019, 0x9d01, 0x6212, 0x0024, 0x001e, 0x5c01, 0x2801, 0x0b55, + 0x6012, 0x0024, 0x0000, 0x0024, 0x2801, 0x0d45, 0x0000, 0x0024, 0x001b, + 0x5bc1, 0x6212, 0x0024, 0x001b, 0xdd81, 0x2801, 0x1115, 0x6012, 0x0024, + 0x0000, 0x0024, 0x2801, 0x1115, 0x0000, 0x0024, 0x0000, 0x004d, 0x000a, + 0xbf4f, 0x280a, 0xb880, 0x0001, 0x0e4e, 0x0020, 0xfb4f, 0x0000, 0x190d, + 0x0001, 0x154e, 0x2920, 0xf440, 0x3009, 0x2bc1, 0x291a, 0x8a40, 0x36e3, + 0x0024, 0x0000, 0x190d, 0x000a, 0x708f, 0x280a, 0xcac0, 0x0000, 0xd7ce, + 0x0030, 0x0017, 0x3700, 0x4024, 0x0000, 0x0200, 0xb102, 0x0024, 0x0000, + 0x00c0, 0x2801, 0x1445, 0x0005, 0x4f92, 0x2909, 0xf840, 0x3613, 0x2800, + 0x0006, 0x0197, 0x0006, 0xa115, 0xb080, 0x0024, 0x3f00, 0x3400, 0x0000, + 0x190d, 0x000a, 0x708f, 0x280a, 0xc0c0, 0x0000, 0xd7ce, 0x0000, 0x004d, + 0x0020, 0xfe0f, 0x2820, 0xfb40, 0x0001, 0x164e, 0x2801, 0x1815, 0x3009, + 0x1000, 0x6012, 0x93cc, 0x0000, 0x0024, 0x2801, 0x32c5, 0x0000, 0x0024, + 0x3413, 0x0024, 0x34b0, 0x0024, 0x4080, 0x0024, 0x0000, 0x0200, 0x2801, + 0x1b15, 0xb882, 0x0024, 0x3453, 0x0024, 0x3009, 0x13c0, 0x4080, 0x0024, + 0x0000, 0x0200, 0x2801, 0x32c5, 0x0000, 0x0024, 0xb882, 0x130c, 0x0000, + 0x004d, 0x0021, 0x058f, 0x2821, 0x0340, 0x0001, 0x1c0e, 0x2801, 0x2c55, + 0x6012, 0x0024, 0x0000, 0x0024, 0x2801, 0x2c55, 0x0000, 0x0024, 0x34c3, + 0x184c, 0x3e13, 0xb80f, 0xf400, 0x4500, 0x0026, 0x9dcf, 0x0001, 0x200e, + 0x0000, 0xfa0d, 0x2926, 0x8e80, 0x3e10, 0x110c, 0x36f3, 0x0024, 0x2801, + 0x2c40, 0x36f3, 0x980f, 0x001c, 0xdd00, 0x001c, 0xd901, 0x6ec2, 0x0024, + 0x001c, 0xdd00, 0x2801, 0x2315, 0x0018, 0xdbc1, 0x3413, 0x184c, 0xf400, + 0x4500, 0x2926, 0xc640, 0x3e00, 0x13cc, 0x2801, 0x2a00, 0x36f3, 0x0024, + 0x6ec2, 0x0024, 0x003f, 0xc000, 0x2801, 0x2595, 0x002a, 0x4001, 0x3413, + 0x184c, 0xf400, 0x4500, 0x2926, 0xafc0, 0x3e00, 0x13cc, 0x2801, 0x2a00, + 0x36f3, 0x0024, 0xb400, 0x0024, 0xd100, 0x0024, 0x0000, 0x0024, 0x2801, + 0x2a05, 0x0000, 0x0024, 0x3613, 0x0024, 0x3e11, 0x4024, 0x2926, 0x8540, + 0x3e01, 0x0024, 0x4080, 0x1b8c, 0x0000, 0x0024, 0x2801, 0x2a05, 0x0000, + 0x0024, 0x3413, 0x184c, 0xf400, 0x4500, 0x2926, 0x8e80, 0x3e10, 0x13cc, + 0x36f3, 0x0024, 0x3110, 0x8024, 0x31f0, 0xc024, 0x0000, 0x4000, 0x0000, + 0x0021, 0x6d06, 0x0024, 0x3110, 0x8024, 0x2826, 0xa8c4, 0x31f0, 0xc024, + 0x2a26, 0xad00, 0x34c3, 0x184c, 0x3410, 0x8024, 0x3430, 0xc024, 0x0000, + 0x4000, 0x0000, 0x0021, 0x6d06, 0x0024, 0x0000, 0x0024, 0x2801, 0x32d4, + 0x4d06, 0x0024, 0x0000, 0x0200, 0x2922, 0x1885, 0x0001, 0x3148, 0x0000, + 0x0200, 0x3e10, 0x8024, 0x2921, 0xca80, 0x3e00, 0xc024, 0x291a, 0x8a40, + 0x0000, 0x0024, 0x2922, 0x1880, 0x36f3, 0x0024, 0x0000, 0x004d, 0x0021, + 0x0ecf, 0x2821, 0x0bc0, 0x0001, 0x324e, 0x2801, 0x1540, 0x3c30, 0x4024, + 0x0000, 0x190d, 0x0001, 0x33ce, 0x2821, 0x0f80, 0x0021, 0x420f, 0x0000, + 0x190d, 0x3e00, 0x0024, 0x2801, 0xe840, 0x0021, 0x42c8, 0x0020, 0xcd4f, + 0x2820, 0xc780, 0x0001, 0x358e, 0x0006, 0xf017, 0x0000, 0x0015, 0xb070, + 0xbc15, 0x0001, 0x374e, 0x0020, 0xdf0f, 0x2820, 0xcd80, 0x0000, 0x190d, + 0x3e00, 0x23c1, 0x2801, 0xe840, 0x0020, 0xdfc8, 0x3613, 0x0024, 0x3e10, + 0xb803, 0x3e14, 0x3811, 0x3e11, 0x3805, 0x3e00, 0x3801, 0x0007, 0xc390, + 0x0006, 0xa011, 0x3010, 0x0444, 0x3050, 0x4405, 0x6458, 0x0302, 0xff94, + 0x4081, 0x0003, 0xffc5, 0x48b6, 0x0024, 0xff82, 0x0024, 0x42b2, 0x0042, + 0xb458, 0x0003, 0x4cd6, 0x9801, 0xf248, 0x1bc0, 0xb58a, 0x0024, 0x6de6, + 0x1804, 0x0006, 0x0010, 0x3810, 0x9bc5, 0x3800, 0xc024, 0x36f4, 0x1811, + 0x36f0, 0x9803, 0x283e, 0x2d80, 0x0fff, 0xffc3, 0x2801, 0x4c80, 0x0000, + 0x0024, 0x3413, 0x0024, 0x2801, 0x4085, 0xf400, 0x4517, 0x2801, 0x4480, + 0x6894, 0x13cc, 0x37b0, 0x184c, 0x6090, 0x1d51, 0x0000, 0x0910, 0x3f00, + 0x060c, 0x3100, 0x4024, 0x6016, 0xb812, 0x000c, 0x8012, 0x2801, 0x4311, + 0xb884, 0x0024, 0x6894, 0x3002, 0x0000, 0x028d, 0x003a, 0x5e0f, 0x0001, + 0x548e, 0x2939, 0xb0c0, 0x3e10, 0x93cc, 0x4084, 0x9bd2, 0x4282, 0x0024, + 0x0000, 0x0040, 0x2801, 0x4685, 0x4292, 0x130c, 0x3443, 0x0024, 0x2801, + 0x47c5, 0x000c, 0x8390, 0x2a01, 0x4b40, 0x3444, 0x0024, 0x3073, 0x0024, + 0xc090, 0x014c, 0x2801, 0x4b40, 0x3800, 0x0024, 0x000c, 0x4113, 0xb880, + 0x2380, 0x3304, 0x4024, 0x3800, 0x05cc, 0xcc92, 0x05cc, 0x3910, 0x0024, + 0x3910, 0x4024, 0x000c, 0x8110, 0x3910, 0x0024, 0x39f0, 0x4024, 0x3810, + 0x0024, 0x38d0, 0x4024, 0x3810, 0x0024, 0x38f0, 0x4024, 0x34c3, 0x0024, + 0x3444, 0x0024, 0x3073, 0x0024, 0x3063, 0x0024, 0x3000, 0x0024, 0x4080, + 0x0024, 0x0000, 0x0024, 0x2839, 0x53d5, 0x4284, 0x0024, 0x3613, 0x0024, + 0x2801, 0x4e85, 0x6898, 0xb804, 0x0000, 0x0084, 0x293b, 0x1cc0, 0x3613, + 0x0024, 0x000c, 0x8117, 0x3711, 0x0024, 0x37d1, 0x4024, 0x4e8a, 0x0024, + 0x0000, 0x0015, 0x2801, 0x5145, 0xce9a, 0x0024, 0x3f11, 0x0024, 0x3f01, + 0x4024, 0x000c, 0x8197, 0x408a, 0x9bc4, 0x3f15, 0x4024, 0x2801, 0x5385, + 0x4284, 0x3c15, 0x6590, 0x0024, 0x0000, 0x0024, 0x2839, 0x53d5, 0x4284, + 0x0024, 0x0000, 0x0024, 0x2801, 0x3f58, 0x458a, 0x0024, 0x2a39, 0x53c0, + 0x003e, 0x2d4f, 0x283a, 0x5ed5, 0x0001, 0x380e, 0x000c, 0x4653, 0x0000, + 0x0246, 0xffac, 0x0c01, 0x48be, 0x0024, 0x4162, 0x4546, 0x6642, 0x4055, + 0x3501, 0x8024, 0x0000, 0x0087, 0x667c, 0x4057, 0x000c, 0x41d5, 0x283a, + 0x62d5, 0x3501, 0x8024, 0x667c, 0x1c47, 0x3701, 0x8024, 0x283a, 0x62d5, + 0xc67c, 0x0024, 0x0000, 0x0024, 0x283a, 0x62c5, 0x0000, 0x0024, 0x2a3a, + 0x5ec0, 0x3009, 0x3851, 0x3e14, 0xf812, 0x3e12, 0xb817, 0x3e11, 0x8024, + 0x0006, 0x0293, 0x3301, 0x8024, 0x468c, 0x3804, 0x0006, 0xa057, 0x2801, + 0x6084, 0x0006, 0x0011, 0x469c, 0x0024, 0x3be1, 0x8024, 0x2801, 0x6095, + 0x0006, 0xc392, 0x3311, 0x0024, 0x33f1, 0x2844, 0x3009, 0x2bc4, 0x0030, + 0x04d2, 0x3311, 0x0024, 0x3a11, 0x0024, 0x3201, 0x8024, 0x003f, 0xfc04, + 0xb64c, 0x0fc4, 0xc648, 0x0024, 0x3a01, 0x0024, 0x3111, 0x1fd3, 0x6498, + 0x07c6, 0x868c, 0x2444, 0x0023, 0xffd2, 0x3901, 0x8e06, 0x0030, 0x0551, + 0x3911, 0x8e06, 0x3961, 0x9c44, 0xf400, 0x44c6, 0xd46c, 0x1bc4, 0x36f1, + 0xbc13, 0x2801, 0x6a15, 0x36f2, 0x9817, 0x002b, 0xffd2, 0x3383, 0x188c, + 0x3e01, 0x8c06, 0x0006, 0xa097, 0x3009, 0x1c12, 0x3213, 0x0024, 0x468c, + 0xbc12, 0x002b, 0xffd2, 0xf400, 0x4197, 0x2801, 0x6704, 0x3713, 0x0024, + 0x2801, 0x6745, 0x37e3, 0x0024, 0x3009, 0x2c17, 0x3383, 0x0024, 0x3009, + 0x0c06, 0x468c, 0x4197, 0x0006, 0xa052, 0x2801, 0x6944, 0x3713, 0x2813, + 0x2801, 0x6985, 0x37e3, 0x0024, 0x3009, 0x2c17, 0x36f1, 0x8024, 0x36f2, + 0x9817, 0x36f4, 0xd812, 0x2100, 0x0000, 0x3904, 0x5bd1, 0x2a01, 0x5a4e, + 0x3e11, 0x7804, 0x0030, 0x0257, 0x3701, 0x0024, 0x0013, 0x4d05, 0xd45b, + 0xe0e1, 0x0007, 0xc795, 0x2801, 0x7195, 0x0fff, 0xff45, 0x3511, 0x184c, + 0x4488, 0xb808, 0x0006, 0x8a97, 0x2801, 0x7145, 0x3009, 0x1c40, 0x3511, + 0x1fc1, 0x0000, 0x0020, 0xac52, 0x1405, 0x6ce2, 0x0024, 0x0000, 0x0024, + 0x2801, 0x7141, 0x68c2, 0x0024, 0x291a, 0x8a40, 0x3e10, 0x0024, 0x2921, + 0xca80, 0x3e00, 0x4024, 0x36f3, 0x0024, 0x3009, 0x1bc8, 0x36f0, 0x1801, + 0x3601, 0x5804, 0x3e13, 0x780f, 0x3e13, 0xb808, 0x0008, 0x9b0f, 0x0001, + 0x744e, 0x2908, 0x9300, 0x0000, 0x004d, 0x36f3, 0x9808, 0x2000, 0x0000, + 0x36f3, 0x580f, 0x0007, 0x81d7, 0x3711, 0x8024, 0x3711, 0xc024, 0x3700, + 0x0024, 0x0000, 0x2001, 0xb012, 0x0024, 0x0034, 0x0000, 0x2801, 0x79c5, + 0x0000, 0x01c1, 0x3700, 0x0024, 0x0002, 0x0001, 0xb012, 0x0024, 0x002e, + 0xe001, 0x2801, 0x78c5, 0x6512, 0x0024, 0x0034, 0x0000, 0x2801, 0x79d5, + 0x0000, 0x01c1, 0x0030, 0x0117, 0x3f00, 0x0024, 0x0014, 0xc000, 0x0000, + 0x01c1, 0x4fce, 0x0024, 0xffea, 0x0024, 0x48b6, 0x0024, 0x4384, 0x4097, + 0xb886, 0x45c6, 0xfede, 0x0024, 0x4db6, 0x0024, 0x466c, 0x0024, 0x0006, + 0xc610, 0x8dd6, 0x8007, 0x0000, 0x00c6, 0xff6e, 0x0024, 0x48b2, 0x0024, + 0x0034, 0x2406, 0xffee, 0x0024, 0x2914, 0xaa80, 0x40b2, 0x0024, 0xf1c6, + 0x0024, 0xf1d6, 0x0024, 0x0000, 0x0201, 0x8d86, 0x0024, 0x61de, 0x0024, + 0x0006, 0xc612, 0x2801, 0x8041, 0x0006, 0xc713, 0x4c86, 0x0024, 0x2912, + 0x1180, 0x0006, 0xc351, 0x0006, 0x0210, 0x2912, 0x0d00, 0x3810, 0x984c, + 0xf200, 0x2043, 0x2808, 0xa000, 0x3800, 0x0024, 0x3e12, 0xb817, 0x3e12, + 0x7808, 0x3e11, 0xb811, 0x3e15, 0x7810, 0x3e18, 0xb823, 0x3e18, 0x3821, + 0x3e10, 0x3801, 0x48b2, 0x0024, 0x3e10, 0x3801, 0x3e11, 0x3802, 0x3009, + 0x3814, 0x0030, 0x0717, 0x3f05, 0xc024, 0x0030, 0x0351, 0x3100, 0x0024, + 0x4080, 0x0024, 0x0030, 0x10d1, 0x2801, 0x8d45, 0x0001, 0x800a, 0x0006, + 0x6514, 0x3111, 0x8024, 0x6894, 0x13c1, 0x6618, 0x0024, 0xfe44, 0x1000, + 0x4cb2, 0x0406, 0x3c10, 0x0024, 0x3c50, 0x4024, 0x34f0, 0x4024, 0x661c, + 0x1040, 0xfe64, 0x0024, 0x4cb2, 0x0024, 0x3cf0, 0x4024, 0xbc82, 0x3080, + 0x0030, 0x0351, 0x3100, 0x8024, 0xfea8, 0x0024, 0x5ca2, 0x0024, 0x0000, + 0x0182, 0xac22, 0x0024, 0xf7c8, 0x0024, 0x48b2, 0x0024, 0xac22, 0x0024, + 0x2801, 0x90c0, 0xf7cc, 0x1002, 0x0030, 0x0394, 0x3400, 0x4024, 0x3100, + 0x184c, 0x0006, 0xc051, 0x291e, 0x8080, 0x0006, 0x6410, 0x4088, 0x1001, + 0x0030, 0x1111, 0x3100, 0x184c, 0x0006, 0xc051, 0x291e, 0x8080, 0x0006, + 0x6550, 0x0006, 0x6694, 0x408c, 0x1002, 0xf224, 0x0024, 0x0006, 0xa017, + 0x2801, 0x94d5, 0x0000, 0x0024, 0x2808, 0x3f41, 0x0006, 0x6410, 0x3050, + 0x0024, 0x3000, 0x4024, 0x6014, 0x0024, 0x0000, 0x0024, 0x2801, 0x9419, + 0x0000, 0x0024, 0xf400, 0x4040, 0x38b0, 0x0024, 0x2808, 0x3f40, 0x3800, + 0x0024, 0x2801, 0x96c1, 0xf224, 0x0024, 0x0000, 0x0024, 0x2808, 0x3f45, + 0x4684, 0x4106, 0xf12c, 0x0024, 0xf148, 0x0024, 0x846c, 0x0024, 0x2808, + 0x3f40, 0xf400, 0x4184, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, + 0x3625, 0x0024, 0x0000, 0x800a, 0x3e10, 0x3801, 0x3e10, 0xb803, 0x3e11, + 0x3805, 0x3e11, 0xb807, 0x3e14, 0x3811, 0x0006, 0xa090, 0x2912, 0x0d00, + 0x3e14, 0xc024, 0x4088, 0x8000, 0x4080, 0x0024, 0x0007, 0x90d1, 0x2801, + 0x9d05, 0x0000, 0x0024, 0x0007, 0x9051, 0x3100, 0x4024, 0x4100, 0x0024, + 0x3900, 0x0024, 0x0007, 0x90d1, 0x0004, 0x0000, 0x31f0, 0x4024, 0x6014, + 0x0400, 0x0000, 0x0024, 0x2801, 0xa151, 0x4080, 0x0024, 0x0000, 0x0000, + 0x2801, 0xa0c5, 0x0000, 0x0024, 0x0007, 0x9053, 0x3300, 0x0024, 0x4080, + 0x0024, 0x0000, 0x0000, 0x2801, 0xa158, 0x0000, 0x0024, 0x0007, 0x9051, + 0x3900, 0x0024, 0x3200, 0x504c, 0x6410, 0x0024, 0x3cf0, 0x0000, 0x4080, + 0x0024, 0x0006, 0xc691, 0x2801, 0xba05, 0x3009, 0x0400, 0x0007, 0x9051, + 0x0000, 0x1001, 0x3100, 0x0024, 0x6012, 0x0024, 0x0006, 0xc6d0, 0x2801, + 0xae49, 0x003f, 0xe000, 0x0006, 0xc693, 0x3900, 0x0c00, 0x3009, 0x0001, + 0x6014, 0x0024, 0x0007, 0x1ad0, 0x2801, 0xae55, 0x3009, 0x0000, 0x4080, + 0x0024, 0x0000, 0x0301, 0x2801, 0xa845, 0x4090, 0x0024, 0x0000, 0x0024, + 0x2801, 0xa955, 0x0000, 0x0024, 0x3009, 0x0000, 0xc012, 0x0024, 0x2801, + 0xae40, 0x3009, 0x2001, 0x3009, 0x0000, 0x6012, 0x0024, 0x0000, 0x0341, + 0x2801, 0xab55, 0x0000, 0x0024, 0x6190, 0x0024, 0x2801, 0xae40, 0x3009, + 0x2000, 0x6012, 0x0024, 0x0000, 0x0381, 0x2801, 0xad15, 0x0000, 0x0024, + 0x6190, 0x0024, 0x2801, 0xae40, 0x3009, 0x2000, 0x6012, 0x0024, 0x0000, + 0x00c0, 0x2801, 0xae55, 0x0000, 0x0024, 0x3009, 0x2000, 0x0006, 0xa090, + 0x3009, 0x0000, 0x4080, 0x0024, 0x0000, 0x0081, 0x2801, 0xb315, 0x0007, + 0x8c13, 0x3300, 0x104c, 0xb010, 0x0024, 0x0002, 0x8001, 0x2801, 0xb585, + 0x34f0, 0x0024, 0x2801, 0xb300, 0x0000, 0x0024, 0x0006, 0xc351, 0x3009, + 0x0000, 0x6090, 0x0024, 0x3009, 0x2000, 0x2900, 0x0b80, 0x3009, 0x0405, + 0x0006, 0xc690, 0x0006, 0xc6d1, 0x3009, 0x0000, 0x3009, 0x0401, 0x6014, + 0x0024, 0x0006, 0xa093, 0x2801, 0xb191, 0xb880, 0x0024, 0x2801, 0xc2c0, + 0x3009, 0x2c00, 0x4040, 0x0024, 0x6012, 0x0024, 0x0006, 0xc6d0, 0x2801, + 0xc2d8, 0x0000, 0x0024, 0x0006, 0xc693, 0x3009, 0x0c00, 0x3009, 0x0001, + 0x6014, 0x0024, 0x0006, 0xc350, 0x2801, 0xc2c1, 0x0000, 0x0024, 0x6090, + 0x0024, 0x3009, 0x2c00, 0x3009, 0x0005, 0x2900, 0x0b80, 0x0001, 0xc2c8, + 0x3009, 0x0400, 0x4080, 0x0024, 0x0003, 0x8000, 0x2801, 0xc2c5, 0x0000, + 0x0024, 0x6400, 0x0024, 0x0000, 0x0081, 0x2801, 0xc2c9, 0x0000, 0x0024, + 0x0007, 0x8c13, 0x3300, 0x0024, 0xb010, 0x0024, 0x0006, 0xc650, 0x2801, + 0xc2d5, 0x0000, 0x0024, 0x0001, 0x0002, 0x3413, 0x0000, 0x3009, 0x0401, + 0x4010, 0x8406, 0x0000, 0x0281, 0xa010, 0x13c1, 0x4122, 0x0024, 0x0000, + 0x03c2, 0x6122, 0x8002, 0x462c, 0x0024, 0x469c, 0x0024, 0xfee2, 0x0024, + 0x48be, 0x0024, 0x6066, 0x8400, 0x0006, 0xc350, 0x2801, 0xc2c1, 0x0000, + 0x0024, 0x4090, 0x0024, 0x3009, 0x2400, 0x2900, 0x0b80, 0x3009, 0x0005, + 0x0007, 0x1b50, 0x2912, 0x0d00, 0x3613, 0x0024, 0x3a00, 0x0380, 0x4080, + 0x0024, 0x0000, 0x00c1, 0x2801, 0xcb85, 0x3009, 0x0000, 0xb010, 0x008c, + 0x4192, 0x0024, 0x6012, 0x0024, 0x0006, 0xf051, 0x2801, 0xc998, 0x3009, + 0x0400, 0x0007, 0x1fd1, 0x30e3, 0x0400, 0x4080, 0x0024, 0x0000, 0x0301, + 0x2801, 0xcb85, 0x3009, 0x0000, 0xb010, 0x0024, 0x0000, 0x0101, 0x6012, + 0x0024, 0x0006, 0xf051, 0x2801, 0xcb95, 0x0000, 0x0024, 0x3023, 0x0400, + 0xf200, 0x184c, 0xb880, 0xa400, 0x3009, 0x2000, 0x3009, 0x0441, 0x3e10, + 0x4402, 0x2909, 0xa9c0, 0x3e10, 0x8024, 0x36e3, 0x0024, 0x36f4, 0xc024, + 0x36f4, 0x1811, 0x36f1, 0x9807, 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f0, + 0x1801, 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, + 0x36f2, 0x9817, 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, + 0xb814, 0x3615, 0x0024, 0x0000, 0x800a, 0x3e10, 0x3801, 0x3e10, 0xb803, + 0x3e11, 0x3805, 0x3e11, 0xf810, 0x0001, 0x0010, 0x3e14, 0x7812, 0xb882, + 0x3813, 0x2914, 0xbec0, 0x0000, 0x2200, 0xb886, 0x12cc, 0x2801, 0xd800, + 0x3454, 0x8024, 0x0001, 0x0000, 0x3000, 0x984c, 0x4234, 0xb843, 0xf400, + 0x4095, 0x003b, 0xffc2, 0x3500, 0x4024, 0xb122, 0x0842, 0x4010, 0x0bc3, + 0x4010, 0x0024, 0x4010, 0x0024, 0x4010, 0x0024, 0x4d82, 0x4011, 0x2938, + 0x0600, 0xf400, 0x4450, 0x3223, 0x184c, 0x3210, 0x8024, 0x32d0, 0xc024, + 0x2938, 0x0600, 0x4d82, 0x4450, 0x3243, 0x1bc3, 0x6396, 0x0024, 0x0005, + 0xdf90, 0x3000, 0x0024, 0x6302, 0x0024, 0x0005, 0xe110, 0x2801, 0xd2d1, + 0x0000, 0x0024, 0x2801, 0xde80, 0x4086, 0x0024, 0x3200, 0x930c, 0x6398, + 0x1111, 0x4244, 0x0844, 0xf400, 0x4095, 0x3500, 0x584c, 0x4438, 0x0805, + 0x453a, 0x4115, 0x3500, 0x8024, 0x6122, 0x4155, 0x4280, 0x1404, 0x0001, + 0x0002, 0x4244, 0x0024, 0x4244, 0x0024, 0x4244, 0x0024, 0x4244, 0x0024, + 0x2938, 0x2f80, 0xf400, 0x4090, 0x6396, 0x0024, 0x0005, 0xdf50, 0x3000, + 0x0024, 0x6302, 0x0024, 0x0005, 0xe0d2, 0x2801, 0xda11, 0x0000, 0x0381, + 0x3073, 0x0024, 0x3023, 0x0024, 0x3000, 0x0024, 0x6012, 0x0024, 0x0001, + 0x2212, 0x2801, 0xe395, 0x0005, 0x1453, 0x0001, 0x0011, 0x3093, 0x184c, + 0x3000, 0x4024, 0x2900, 0x78c0, 0x3e00, 0x4024, 0x2801, 0xe580, 0x36f3, + 0x0024, 0x0005, 0xe3c1, 0x0001, 0x0011, 0x3613, 0x024c, 0x3e10, 0x4024, + 0x3000, 0x8024, 0x2900, 0x5c40, 0x3e00, 0x8024, 0x36e3, 0x0024, 0x36f4, + 0xc024, 0x36f4, 0x5812, 0x36f1, 0xd810, 0x36f1, 0x1805, 0x36f0, 0x9803, + 0x36f0, 0x1801, 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, + 0x0000, 0x36f2, 0x9817, 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, + 0x3e05, 0xb814, 0x3625, 0x0024, 0x0000, 0x800a, 0x3e10, 0x3801, 0x0000, + 0x00c1, 0xb880, 0xb803, 0x3e10, 0x904c, 0x3e11, 0x3806, 0x3e11, 0xf810, + 0x0006, 0xf450, 0x3e14, 0x7812, 0x3e14, 0xc024, 0x3cf0, 0x2080, 0x3009, + 0x23c0, 0x3009, 0x2380, 0x0000, 0x0640, 0x3009, 0x2000, 0x2921, 0x9440, + 0x0000, 0x00c0, 0x2921, 0xdd40, 0x3613, 0x0024, 0xf400, 0x4004, 0x0000, + 0x01c0, 0x6400, 0x0024, 0x0000, 0x00c0, 0x2802, 0x0885, 0x0000, 0x01c1, + 0x6412, 0x4100, 0x0006, 0x0581, 0x2801, 0xfe01, 0x4412, 0x0024, 0xf400, + 0x4057, 0x3702, 0x0024, 0x2000, 0x0000, 0x0000, 0x0024, 0x0006, 0xf410, + 0x0000, 0x0641, 0x3613, 0x0000, 0x6012, 0x0024, 0x0000, 0x0024, 0x2801, + 0xf3d5, 0x0000, 0x0024, 0x3009, 0x2004, 0x2900, 0xb600, 0x3e01, 0x0024, + 0x2801, 0xfe00, 0x36f3, 0x0024, 0x0006, 0xf410, 0x0000, 0x0641, 0x3613, + 0x0000, 0x6012, 0x0024, 0x0000, 0x0024, 0x2801, 0xf6d5, 0x0000, 0x0024, + 0x3009, 0x2004, 0x2900, 0xa400, 0x3e01, 0x0024, 0x2801, 0xfe00, 0x36f3, + 0x0024, 0x0006, 0xf450, 0x3613, 0x0000, 0x6090, 0x3804, 0x2900, 0xb600, + 0x3009, 0x2000, 0x2801, 0xfe00, 0x36f3, 0x0024, 0x2923, 0x4f00, 0x0007, + 0x2050, 0x2801, 0xfe00, 0x3009, 0x2000, 0x2923, 0x7580, 0x0001, 0xfe08, + 0x34d3, 0x184c, 0x3430, 0x0024, 0x2922, 0x4fc0, 0x3e00, 0x0024, 0x2801, + 0xfe00, 0x36f3, 0x0024, 0x0000, 0x3fc0, 0x0007, 0x2050, 0x3613, 0x0024, + 0x2923, 0x8480, 0x3e00, 0x0024, 0x36f3, 0x2000, 0x0000, 0x1800, 0x3413, + 0x0024, 0xf400, 0x4510, 0x34f0, 0x4024, 0x6192, 0x0024, 0x6014, 0x2001, + 0x0007, 0x2051, 0x2802, 0x0081, 0x0000, 0x0280, 0x3009, 0x2400, 0x3009, + 0x0400, 0x4080, 0x0024, 0x0006, 0xf352, 0x2802, 0x0995, 0x3009, 0x0842, + 0x3009, 0x0bc3, 0x4d86, 0x0024, 0x0000, 0x0201, 0x2802, 0x04c5, 0x0030, + 0x0013, 0x0006, 0x8a93, 0x3009, 0x0c40, 0x3009, 0x0fc1, 0x6cde, 0x0024, + 0x0000, 0x0201, 0x2802, 0x0981, 0x0030, 0x0013, 0x3300, 0x0024, 0xb010, + 0x0024, 0x0000, 0x0100, 0x2802, 0x0995, 0x0000, 0x00c1, 0x2921, 0x9440, + 0x3613, 0x0024, 0x2921, 0xdd40, 0x3613, 0x0024, 0xf400, 0x4004, 0x0000, + 0x01c0, 0x6400, 0x0024, 0x0000, 0x01c1, 0x2801, 0xefd5, 0x0000, 0x00c0, + 0x2921, 0x9440, 0x3613, 0x0024, 0x2921, 0xc300, 0x0000, 0x0024, 0x36f4, + 0xc024, 0x36f4, 0x5812, 0x36f1, 0xd810, 0x36f1, 0x1806, 0x36f0, 0x9803, + 0x36f0, 0x1801, 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, + 0x0000, 0x36f2, 0x9817, 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, + 0x3e05, 0xb814, 0x3615, 0x0024, 0x0000, 0x800a, 0x3e10, 0xb803, 0x0012, + 0x5103, 0x3e11, 0x3805, 0x3e11, 0xb807, 0x3e14, 0x380d, 0x0030, 0x0250, + 0x3e13, 0xf80e, 0xbe8b, 0x83e0, 0x290c, 0x4840, 0x3613, 0x0024, 0x290c, + 0x4840, 0x4086, 0x984c, 0x0000, 0x00ce, 0x2402, 0x138e, 0x3009, 0x1bc0, + 0x0000, 0x01c3, 0xae3a, 0x184c, 0x0000, 0x0043, 0x3009, 0x3842, 0x290c, + 0x4840, 0x3009, 0x3840, 0x4084, 0x9bc0, 0xfe26, 0x9bc2, 0xceba, 0x0024, + 0x4e8e, 0x0024, 0x4e9a, 0x0024, 0x4f8e, 0x0024, 0x0000, 0x0102, 0x2802, + 0x18c5, 0x0030, 0x0010, 0x0000, 0x0206, 0x3613, 0x0024, 0x290c, 0x4840, + 0x3009, 0x3840, 0x3000, 0xdbc0, 0xb366, 0x0024, 0x0000, 0x0024, 0x2802, + 0x18d5, 0x4e8e, 0x0024, 0x4e9a, 0x0024, 0x4f8e, 0x0024, 0x0030, 0x0010, + 0x2802, 0x1595, 0x0000, 0x0206, 0x36f3, 0xd80e, 0x36f4, 0x180d, 0x36f1, + 0x9807, 0x36f1, 0x1805, 0x36f0, 0x9803, 0x3405, 0x9014, 0x36f3, 0x0024, + 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, 0x3613, 0x0024, 0x3e12, + 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, 0x3635, 0x0024, 0x0000, 0x800a, + 0x3e10, 0x3801, 0x3e10, 0xb803, 0x3e11, 0x3805, 0x3e11, 0xb810, 0x3e04, + 0x7812, 0x34d3, 0x0024, 0x3400, 0x0024, 0xf200, 0x1102, 0xf200, 0x0024, + 0xf200, 0x0024, 0x3cf0, 0x0024, 0x2914, 0xba00, 0x0000, 0x1600, 0x0000, + 0x4001, 0x6012, 0x108c, 0x3ce0, 0x0024, 0x2802, 0x2209, 0x0000, 0x0386, + 0x0000, 0x4000, 0x3423, 0x0024, 0x3ce0, 0x0024, 0x0000, 0x0041, 0x3413, + 0x0024, 0x34b0, 0x8024, 0xfe22, 0x1100, 0x48b6, 0x0024, 0xad66, 0x0024, + 0xfe02, 0x0024, 0x2915, 0x8600, 0x48b2, 0x0024, 0x4c8a, 0x104c, 0x0000, + 0x0041, 0x34f0, 0x0024, 0xfe02, 0x0024, 0x0000, 0xf001, 0x6eba, 0x0024, + 0xf040, 0x0024, 0x6012, 0x0024, 0x0000, 0x0041, 0x2802, 0x2a08, 0x0000, + 0xf002, 0xf040, 0x104c, 0x3400, 0xc024, 0xfe26, 0x0024, 0x48b6, 0x0024, + 0xfe02, 0x0024, 0x2915, 0x8600, 0x48b2, 0x0024, 0x4480, 0x33c0, 0x0000, + 0xf004, 0x2802, 0x2a18, 0x0000, 0x0024, 0x003f, 0x1004, 0x0006, 0x0090, + 0x0000, 0x0041, 0xb884, 0x108c, 0x6896, 0xa004, 0x34e0, 0x0024, 0xfe02, + 0x0024, 0x2914, 0xa580, 0x48b2, 0x0024, 0x0006, 0x0110, 0x3423, 0x23c0, + 0x34f0, 0x0024, 0x3410, 0x2380, 0xb880, 0xa140, 0x3009, 0x23c0, 0x3009, + 0x2340, 0x3009, 0x0000, 0x4080, 0x0024, 0x0000, 0xba11, 0x2802, 0x2f95, + 0x0000, 0x0024, 0x2802, 0x3780, 0x3ce4, 0x4024, 0x4080, 0x138c, 0x0000, + 0x0001, 0x2802, 0x3418, 0x0006, 0x0011, 0x0000, 0xba00, 0x6090, 0x108c, + 0x3ce0, 0x0400, 0x6014, 0x0024, 0x0006, 0xa052, 0x2802, 0x3351, 0x0004, + 0x0001, 0x6014, 0x0024, 0x0000, 0x0024, 0x2802, 0x3791, 0x0000, 0x0024, + 0x3009, 0x0800, 0x2802, 0x3780, 0x3009, 0x2400, 0x0000, 0xba00, 0x6090, + 0x108c, 0x6090, 0x0024, 0x3ce0, 0x0400, 0x6014, 0x0024, 0x0006, 0xa052, + 0x2802, 0x3711, 0x0004, 0x0001, 0x6014, 0x0024, 0x0000, 0x0024, 0x2802, + 0x3791, 0x0000, 0x0024, 0x3009, 0x0800, 0x3009, 0x2400, 0x3613, 0x108c, + 0x290f, 0xfdc0, 0x34e4, 0x3810, 0x0000, 0x0810, 0x290f, 0xfcc0, 0x3009, + 0x1bcc, 0x36f4, 0x5812, 0x36f1, 0x9810, 0x36f1, 0x1805, 0x36f0, 0x9803, + 0x36f0, 0x1801, 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, + 0x0000, 0x36f2, 0x9817, 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, + 0x3e05, 0xb814, 0x3615, 0x0024, 0x0000, 0x800a, 0x3e10, 0x3801, 0x3e10, + 0xb803, 0x3e11, 0x3805, 0x3e14, 0x3811, 0x0006, 0x01d1, 0x0006, 0xc610, + 0x3e04, 0xb813, 0x3009, 0x0000, 0x3009, 0x0401, 0x6014, 0x0024, 0x0030, + 0x0312, 0x2802, 0x4355, 0x0000, 0x0024, 0x3200, 0x044c, 0x3009, 0x0401, + 0x6014, 0x0024, 0x0006, 0x0292, 0x2802, 0x4355, 0x0006, 0xc351, 0x3009, + 0x0400, 0x3009, 0x0801, 0x6014, 0x0024, 0x0000, 0x0024, 0x2802, 0x5985, + 0x0000, 0x0024, 0x0030, 0x0311, 0x3100, 0x0024, 0x4080, 0x0024, 0x0010, + 0x0000, 0x2802, 0x4515, 0x0000, 0x0024, 0x3900, 0x0024, 0x3100, 0x0024, + 0x4080, 0x0024, 0x0001, 0xffc0, 0x2802, 0x4b98, 0x0030, 0x00d2, 0x3201, + 0x0024, 0xb408, 0x0024, 0x0006, 0x01d3, 0x2802, 0x47d5, 0x0001, 0xf400, + 0x0001, 0x0c04, 0x4408, 0x0401, 0x3613, 0x2004, 0x0006, 0xc350, 0x6810, + 0xac44, 0x3009, 0x2c81, 0x3e10, 0x0000, 0x2902, 0x1b40, 0x3e00, 0x2c00, + 0x36f3, 0x0000, 0x6090, 0x0024, 0x3009, 0x2000, 0x3009, 0x0005, 0x459a, + 0x0024, 0x2908, 0x9300, 0x0002, 0x5988, 0x3201, 0x0024, 0xb408, 0x0024, + 0x0000, 0x0081, 0x2802, 0x4d15, 0x0006, 0x02d3, 0x0001, 0x0c04, 0x0001, + 0xf400, 0x4408, 0x8c00, 0x6012, 0x044c, 0x3009, 0x184c, 0x2802, 0x4ed5, + 0x0004, 0x0003, 0x4448, 0x0024, 0x39f0, 0x3800, 0xb884, 0x3801, 0x0000, + 0x0041, 0x3100, 0x0024, 0xfe02, 0x0024, 0x2915, 0x8600, 0x48b2, 0x0024, + 0x0006, 0x01d0, 0x0006, 0x02d1, 0xffc0, 0x1bcc, 0x48b2, 0x0024, 0x4cc2, + 0x0024, 0x4cc2, 0x0024, 0x3009, 0x2001, 0x0000, 0x0081, 0x3009, 0x0400, + 0x6012, 0x0024, 0x0006, 0xc353, 0x2802, 0x5595, 0x0030, 0x0312, 0x3200, + 0x404c, 0x3613, 0x2001, 0x3e10, 0x4c01, 0xf212, 0x0024, 0x3e00, 0x4024, + 0x2902, 0x1b40, 0x0002, 0x56c8, 0x3200, 0x404c, 0x3613, 0x2001, 0x3e10, + 0x4c01, 0x2902, 0x1b40, 0x3e00, 0x4024, 0x3023, 0x0c00, 0x36f3, 0x2340, + 0x3009, 0x0000, 0x0006, 0xc610, 0x3009, 0x2000, 0x3009, 0x0c00, 0x6090, + 0x0024, 0x3009, 0x2c00, 0x3009, 0x0c05, 0x2908, 0x9300, 0x459a, 0x0024, + 0x36f4, 0x9813, 0x36f4, 0x1811, 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f0, + 0x1801, 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, + 0x36f2, 0x9817, 0x3613, 0x0024, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, + 0xb814, 0x3615, 0x0024, 0x0000, 0x800a, 0x3e10, 0xb803, 0x3e11, 0x3811, + 0x3e14, 0xb813, 0x3e13, 0xf80e, 0x2902, 0x3b80, 0x3e03, 0x4024, 0x4194, + 0x0024, 0x002b, 0x1103, 0x2802, 0x7355, 0x0006, 0xc351, 0x3009, 0x0402, + 0x6236, 0x0024, 0x0010, 0x0003, 0x2802, 0x7351, 0x0030, 0x0311, 0x3100, + 0x8024, 0x6236, 0x0024, 0x0000, 0x0024, 0x2802, 0x7105, 0x0000, 0x0024, + 0x3100, 0x8024, 0x4284, 0x0024, 0x0006, 0x0793, 0x2802, 0x7109, 0x0000, + 0x0024, 0xf100, 0x0012, 0xb888, 0x4491, 0x3300, 0x8024, 0x0006, 0x0753, + 0x6404, 0x2c02, 0x0000, 0x0024, 0x2802, 0x6818, 0x4094, 0x0024, 0x2402, + 0x6782, 0x3613, 0x0024, 0x3220, 0x3840, 0x2902, 0xafc0, 0x32e0, 0x7801, + 0x3243, 0x1bc1, 0x6498, 0x0024, 0x3920, 0x1800, 0x36f3, 0x0024, 0x0006, + 0x0753, 0xb888, 0x0c02, 0x0006, 0x0793, 0x3b10, 0x8024, 0x3004, 0x8024, + 0x3300, 0x884c, 0x0006, 0x0753, 0x6404, 0x2c02, 0x0000, 0x0024, 0x2802, + 0x6d18, 0x4094, 0x4491, 0x2402, 0x6c82, 0x3613, 0x0024, 0x3220, 0x3840, + 0x2902, 0xafc0, 0x32e0, 0x7801, 0x3243, 0x1bc1, 0x6498, 0x0024, 0x3920, + 0x1800, 0x36f3, 0x0024, 0x0006, 0x0753, 0x0000, 0x0083, 0x3300, 0x984c, + 0x0006, 0x07d3, 0x3b00, 0x8024, 0x0006, 0x02d3, 0x3009, 0x0c02, 0x6236, + 0x0024, 0x0000, 0x0082, 0x2802, 0x7085, 0x0000, 0x0024, 0xb884, 0xac02, + 0x0006, 0x0293, 0x3009, 0x2c02, 0x2802, 0x7340, 0x3009, 0x1bcc, 0x0006, + 0x02d2, 0x3613, 0x0802, 0x4294, 0x0024, 0x0006, 0x0293, 0x2802, 0x7305, + 0x6894, 0x0024, 0xb884, 0xa802, 0x3009, 0x2c02, 0x3009, 0x1bcc, 0x36f3, + 0x4024, 0x36f3, 0xd80e, 0x36f4, 0x9813, 0x36f1, 0x1811, 0x36f0, 0x9803, + 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, + 0x9817, 0x3613, 0x0024, 0x3e22, 0xb815, 0x3e05, 0xb814, 0xb880, 0x1854, + 0x3e10, 0xb811, 0x0007, 0x9251, 0xb884, 0x3812, 0x0006, 0x0792, 0x3900, + 0xb813, 0x0006, 0x0753, 0x0006, 0x1002, 0x0002, 0x5c11, 0x3a10, 0x8024, + 0x0006, 0x8002, 0x3a00, 0x8024, 0x0006, 0x1002, 0x0007, 0x9252, 0x3b00, + 0x9813, 0x3a04, 0x4024, 0x36f4, 0x8024, 0x36f0, 0x9811, 0x3405, 0x9014, + 0x36e3, 0x0024, 0x2000, 0x0000, 0x36f2, 0x9815, 0x3009, 0x3857, 0x3e18, + 0x3822, 0x3e18, 0x780a, 0x3e10, 0x3801, 0x48b2, 0x3855, 0x3e10, 0x3801, + 0x0000, 0x800a, 0x3e14, 0x3811, 0x3e14, 0xb813, 0x0006, 0x0013, 0x0023, + 0xffd1, 0x0006, 0x0192, 0x3009, 0x0800, 0x4080, 0x8c10, 0x0030, 0x0552, + 0x2802, 0x8bc5, 0xf400, 0x4401, 0x0006, 0x0093, 0x3e10, 0xb803, 0x3e01, + 0x0c40, 0x4000, 0x8cc4, 0x4010, 0x8c02, 0x0000, 0x0001, 0x6010, 0x4012, + 0x0006, 0x0113, 0x2802, 0x8398, 0x6428, 0x8c80, 0x0004, 0x0013, 0x3283, + 0x0024, 0x0006, 0x0193, 0x3009, 0x0203, 0x3009, 0x0c02, 0xfe26, 0x0024, + 0x48b6, 0x8841, 0xfe42, 0x0024, 0x4db6, 0x0024, 0xffb0, 0x4003, 0x48b2, + 0x0024, 0xffa6, 0x8203, 0x40b2, 0x8f82, 0x0030, 0x0555, 0x3d10, 0x4c80, + 0xfe26, 0x0024, 0x48b6, 0x8bc1, 0xfe42, 0x0024, 0x4db6, 0x0024, 0xffb0, + 0x4003, 0x48b2, 0x0024, 0xffa6, 0x1bc4, 0x40b2, 0x8c02, 0x4290, 0x3401, + 0x3009, 0x2f00, 0x2802, 0x8c95, 0x3009, 0x0c00, 0x4000, 0x4401, 0x4100, + 0x0024, 0x0000, 0x0001, 0x6014, 0x4010, 0x0004, 0x0001, 0x2802, 0x8c98, + 0x4010, 0x0024, 0x2802, 0x8c80, 0xf400, 0x4010, 0x3e00, 0x8200, 0x3a10, + 0x0200, 0x3a00, 0x3803, 0x0006, 0x0152, 0x6104, 0x8b00, 0x6090, 0x8901, + 0x6014, 0xa800, 0x0006, 0xa053, 0x2802, 0x8f48, 0xb880, 0x4402, 0x3009, + 0x2b80, 0x3009, 0x08c0, 0x4090, 0x4402, 0x3009, 0x2800, 0x0006, 0x0012, + 0x3009, 0x2810, 0x3009, 0x0c01, 0x6214, 0x0024, 0x0006, 0x0092, 0x2802, + 0x9198, 0x0000, 0x0100, 0x0004, 0x0001, 0x4214, 0x0024, 0x3009, 0x0801, + 0x4112, 0x8c10, 0x6010, 0x020c, 0x6204, 0x020c, 0x3083, 0x1803, 0x2802, + 0x9389, 0x36f0, 0x820c, 0x3009, 0x2c10, 0x36f4, 0x9813, 0x36f4, 0x1811, + 0x36f0, 0x1801, 0x2210, 0x0000, 0x36f5, 0x4024, 0x36f0, 0x1801, 0x36f8, + 0x580a, 0x36f8, 0x1822, 0x0030, 0x0717, 0x2100, 0x0000, 0x3f05, 0xdbd7, + 0x3009, 0x3853, 0x3e18, 0x3823, 0x3e18, 0x780a, 0x3e10, 0x3801, 0x48b2, + 0x0024, 0x3e10, 0x3801, 0x0000, 0x800a, 0x3e10, 0xb803, 0x3e11, 0x3810, + 0x3e04, 0x7812, 0x0006, 0x0010, 0x0006, 0x0191, 0x3009, 0x0400, 0x4080, + 0x8012, 0x0030, 0x0553, 0x2802, 0xa385, 0x3009, 0x0840, 0x0006, 0x0093, + 0x32f3, 0x0c40, 0x4000, 0x4481, 0x4010, 0x8843, 0xf400, 0x4011, 0x0004, + 0x0001, 0x6014, 0x8cc4, 0x0030, 0x0550, 0x2802, 0x9dd1, 0x3009, 0x0f82, + 0x0ffc, 0x0010, 0x3183, 0x0024, 0x0030, 0x0550, 0x6428, 0x184c, 0xfe27, + 0xe6e7, 0x48b6, 0x8447, 0xfe4e, 0x8c87, 0x4db6, 0x0024, 0xffbe, 0x8bc3, + 0x48b2, 0x0024, 0xffae, 0x8f82, 0x40b2, 0x0024, 0xfe26, 0x2041, 0x48b6, + 0x87c7, 0xfe4e, 0x0024, 0x4db6, 0x8c87, 0xffbe, 0x0024, 0x48b2, 0x0024, + 0xffae, 0x0024, 0x40b2, 0x8c02, 0x4290, 0x2001, 0x3009, 0x2c00, 0x2802, + 0xa415, 0x36f1, 0x9807, 0x2802, 0xa400, 0xf400, 0x4452, 0x3b10, 0x0bc0, + 0x3b00, 0x0024, 0x0006, 0x0150, 0x3223, 0x0300, 0x6090, 0x8101, 0x6014, + 0x4484, 0x0004, 0x0001, 0x2802, 0xa708, 0x6414, 0xa300, 0xb880, 0x810c, + 0x3009, 0x2380, 0x3009, 0x00c0, 0x4090, 0x4484, 0x6414, 0xa000, 0x0006, + 0xa051, 0x2802, 0xa891, 0x0006, 0x0010, 0x0ffc, 0x0013, 0x3283, 0x0024, + 0xf400, 0x4484, 0x3009, 0x0400, 0x6408, 0xa012, 0x0000, 0x0400, 0x2802, + 0xaa98, 0x6404, 0x8412, 0x0004, 0x0002, 0x4428, 0x0024, 0x6404, 0x0024, + 0x0000, 0x0413, 0x2802, 0xad08, 0x3283, 0x0024, 0xf400, 0x4480, 0x6014, + 0x0024, 0x0ffc, 0x0013, 0x2802, 0xacd1, 0x0000, 0x0024, 0x3283, 0x0024, + 0x3009, 0x2412, 0x36f4, 0x5812, 0x36f1, 0x1810, 0x36f0, 0x9803, 0x36f0, + 0x1801, 0x2210, 0x0000, 0x36f0, 0x1801, 0x36f8, 0x580a, 0x36f8, 0x1823, + 0x0030, 0x0713, 0x2100, 0x0000, 0x3b04, 0xdbd3, 0x3613, 0x0024, 0x3e12, + 0x8024, 0x3e10, 0xb803, 0x3e14, 0x3811, 0x3e14, 0xb813, 0x3e13, 0x780e, + 0x3e03, 0xc024, 0x0001, 0x000a, 0x0006, 0x0755, 0x3504, 0x0024, 0x0020, + 0x0b91, 0x3880, 0x0024, 0x3880, 0x4024, 0xbd86, 0x3410, 0x0008, 0x2b91, + 0x003f, 0x15d2, 0x0000, 0x0053, 0x0000, 0x058e, 0x2402, 0xb4ce, 0xfe25, + 0x0829, 0x5017, 0x0829, 0x000e, 0x7b91, 0x5016, 0x020c, 0x4db6, 0x0001, + 0x4d16, 0x1bcf, 0xf1d6, 0x980e, 0xf7d0, 0x1bcd, 0x36f4, 0x9813, 0x36f4, + 0x1811, 0x36f0, 0x9803, 0x2000, 0x0000, 0x36f2, 0x8024, 0xb386, 0x40d7, + 0x4284, 0x184c, 0x0000, 0x05c0, 0x2802, 0xb955, 0xf5d8, 0x3804, 0x0000, + 0x0984, 0x6400, 0xb84a, 0x3e13, 0xf80d, 0xa204, 0x380e, 0x0000, 0x800a, + 0x0000, 0x00ce, 0x2402, 0xbc8e, 0xffa4, 0x0024, 0x48b6, 0x0024, 0x0000, + 0x0024, 0x2802, 0xbc84, 0x4000, 0x40c2, 0x4224, 0x0024, 0x6090, 0x0024, + 0xffa4, 0x0024, 0x0fff, 0xfe83, 0xfe86, 0x1bce, 0x36f3, 0xd80d, 0x48b6, + 0x0024, 0x0fff, 0xff03, 0xa230, 0x45c3, 0x2000, 0x0000, 0x36f1, 0x180a, + 0x0007, 0x0001, /*copy 1*/ + 0x802e, 0x0006, 0x0002, /*copy 2*/ + 0x2801, 0x6b00, 0x0007, 0x0001, /*copy 1*/ + 0x8030, 0x0006, 0x0002, /*copy 2*/ + 0x2800, 0x1b40, 0x0007, 0x0001, /*copy 1*/ + 0x8028, 0x0006, 0x0002, /*copy 2*/ + 0x2a00, 0x148e, 0x0007, 0x0001, /*copy 1*/ + 0x8032, 0x0006, 0x0002, /*copy 2*/ + 0x2801, 0x9740, 0x0007, 0x0001, /*copy 1*/ + 0x3580, 0x0006, 0x8038, 0x0000, /*Rle(56)*/ + 0x0007, 0x0001, /*copy 1*/ + 0xfab3, 0x0006, 0x01bc, /*copy 444*/ + 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, 0xffff, 0xfffe, 0xfffb, 0xfff9, + 0xfff5, 0xfff2, 0xffed, 0xffe8, 0xffe3, 0xffde, 0xffd8, 0xffd3, 0xffce, + 0xffca, 0xffc7, 0xffc4, 0xffc4, 0xffc5, 0xffc7, 0xffcc, 0xffd3, 0xffdc, + 0xffe6, 0xfff3, 0x0001, 0x0010, 0x001f, 0x002f, 0x003f, 0x004e, 0x005b, + 0x0066, 0x006f, 0x0074, 0x0075, 0x0072, 0x006b, 0x005f, 0x004f, 0x003c, + 0x0024, 0x0009, 0xffed, 0xffcf, 0xffb0, 0xff93, 0xff77, 0xff5f, 0xff4c, + 0xff3d, 0xff35, 0xff34, 0xff3b, 0xff4a, 0xff60, 0xff7e, 0xffa2, 0xffcd, + 0xfffc, 0x002e, 0x0061, 0x0094, 0x00c4, 0x00f0, 0x0114, 0x0131, 0x0144, + 0x014b, 0x0146, 0x0134, 0x0116, 0x00eb, 0x00b5, 0x0075, 0x002c, 0xffde, + 0xff8e, 0xff3d, 0xfeef, 0xfea8, 0xfe6a, 0xfe39, 0xfe16, 0xfe05, 0xfe06, + 0xfe1b, 0xfe43, 0xfe7f, 0xfecd, 0xff2a, 0xff95, 0x0009, 0x0082, 0x00fd, + 0x0173, 0x01e1, 0x0242, 0x0292, 0x02cc, 0x02ec, 0x02f2, 0x02da, 0x02a5, + 0x0253, 0x01e7, 0x0162, 0x00c9, 0x0021, 0xff70, 0xfebc, 0xfe0c, 0xfd68, + 0xfcd5, 0xfc5b, 0xfc00, 0xfbc9, 0xfbb8, 0xfbd2, 0xfc16, 0xfc85, 0xfd1b, + 0xfdd6, 0xfeae, 0xff9e, 0x009c, 0x01a0, 0x02a1, 0x0392, 0x046c, 0x0523, + 0x05b0, 0x060a, 0x062c, 0x0613, 0x05bb, 0x0526, 0x0456, 0x0351, 0x021f, + 0x00c9, 0xff5a, 0xfde1, 0xfc6a, 0xfb05, 0xf9c0, 0xf8aa, 0xf7d0, 0xf73d, + 0xf6fa, 0xf70f, 0xf77e, 0xf848, 0xf96b, 0xfadf, 0xfc9a, 0xfe8f, 0x00ad, + 0x02e3, 0x051a, 0x073f, 0x0939, 0x0af4, 0x0c5a, 0x0d59, 0x0de1, 0x0de5, + 0x0d5c, 0x0c44, 0x0a9e, 0x0870, 0x05c7, 0x02b4, 0xff4e, 0xfbaf, 0xf7f8, + 0xf449, 0xf0c7, 0xed98, 0xeae0, 0xe8c4, 0xe765, 0xe6e3, 0xe756, 0xe8d2, + 0xeb67, 0xef19, 0xf3e9, 0xf9cd, 0x00b5, 0x088a, 0x112b, 0x1a72, 0x2435, + 0x2e42, 0x3866, 0x426b, 0x4c1b, 0x553e, 0x5da2, 0x6516, 0x6b6f, 0x7087, + 0x7441, 0x7686, 0x774a, 0x7686, 0x7441, 0x7087, 0x6b6f, 0x6516, 0x5da2, + 0x553e, 0x4c1b, 0x426b, 0x3866, 0x2e42, 0x2435, 0x1a72, 0x112b, 0x088a, + 0x00b5, 0xf9cd, 0xf3e9, 0xef19, 0xeb67, 0xe8d2, 0xe756, 0xe6e3, 0xe765, + 0xe8c4, 0xeae0, 0xed98, 0xf0c7, 0xf449, 0xf7f8, 0xfbaf, 0xff4e, 0x02b4, + 0x05c7, 0x0870, 0x0a9e, 0x0c44, 0x0d5c, 0x0de5, 0x0de1, 0x0d59, 0x0c5a, + 0x0af4, 0x0939, 0x073f, 0x051a, 0x02e3, 0x00ad, 0xfe8f, 0xfc9a, 0xfadf, + 0xf96b, 0xf848, 0xf77e, 0xf70f, 0xf6fa, 0xf73d, 0xf7d0, 0xf8aa, 0xf9c0, + 0xfb05, 0xfc6a, 0xfde1, 0xff5a, 0x00c9, 0x021f, 0x0351, 0x0456, 0x0526, + 0x05bb, 0x0613, 0x062c, 0x060a, 0x05b0, 0x0523, 0x046c, 0x0392, 0x02a1, + 0x01a0, 0x009c, 0xff9e, 0xfeae, 0xfdd6, 0xfd1b, 0xfc85, 0xfc16, 0xfbd2, + 0xfbb8, 0xfbc9, 0xfc00, 0xfc5b, 0xfcd5, 0xfd68, 0xfe0c, 0xfebc, 0xff70, + 0x0021, 0x00c9, 0x0162, 0x01e7, 0x0253, 0x02a5, 0x02da, 0x02f2, 0x02ec, + 0x02cc, 0x0292, 0x0242, 0x01e1, 0x0173, 0x00fd, 0x0082, 0x0009, 0xff95, + 0xff2a, 0xfecd, 0xfe7f, 0xfe43, 0xfe1b, 0xfe06, 0xfe05, 0xfe16, 0xfe39, + 0xfe6a, 0xfea8, 0xfeef, 0xff3d, 0xff8e, 0xffde, 0x002c, 0x0075, 0x00b5, + 0x00eb, 0x0116, 0x0134, 0x0146, 0x014b, 0x0144, 0x0131, 0x0114, 0x00f0, + 0x00c4, 0x0094, 0x0061, 0x002e, 0xfffc, 0xffcd, 0xffa2, 0xff7e, 0xff60, + 0xff4a, 0xff3b, 0xff34, 0xff35, 0xff3d, 0xff4c, 0xff5f, 0xff77, 0xff93, + 0xffb0, 0xffcf, 0xffed, 0x0009, 0x0024, 0x003c, 0x004f, 0x005f, 0x006b, + 0x0072, 0x0075, 0x0074, 0x006f, 0x0066, 0x005b, 0x004e, 0x003f, 0x002f, + 0x001f, 0x0010, 0x0001, 0xfff3, 0xffe6, 0xffdc, 0xffd3, 0xffcc, 0xffc7, + 0xffc5, 0xffc4, 0xffc4, 0xffc7, 0xffca, 0xffce, 0xffd3, 0xffd8, 0xffde, + 0xffe3, 0xffe8, 0xffed, 0xfff2, 0xfff5, 0xfff9, 0xfffb, 0xfffe, 0xffff, + 0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, 0xffd8, 0x0052, 0xff62, + 0x0116, 0xfe3a, 0x02c3, 0xfbd5, 0x0633, 0xf6b8, 0x0e89, 0xe5ee, 0x511e, + 0x511e, 0xe5ee, 0x0e89, 0xf6b8, 0x0633, 0xfbd5, 0x02c3, 0xfe3a, 0x0116, + 0xff62, 0x0052, 0xffd8, 0x0007, 0x0001, /*copy 1*/ + 0x180b, 0x0006, 0x0012, /*copy 18*/ + 0x000f, 0x0010, 0x001c, 0xfab3, 0x3580, 0x8037, 0xa037, 0x0001, 0x0000, + 0x3580, 0x01a4, 0x07c7, 0x07d3, 0x07e6, 0x07df, 0x07ea, 0x07ec, 0x07f2, + 0x0007, 0x0001, /*copy 1*/ + 0x8025, 0x0006, 0x0002, /*copy 2*/ + 0x2a01, 0x824e, 0x0007, 0x0001, /*copy 1*/ + 0x5800, 0x0006, 0x0005, /*copy 5*/ + 0x0000, 0x0c00, 0x0000, 0x0100, 0x0100, 0x0006, 0x8006, 0x0000, /*Rle(6)*/ + 0x000a, 0x0001, /*copy 1*/ + 0x0050, +#define PLUGIN_SIZE 5964 +#ifndef SKIP_PLUGIN_VARNAME +}; +#endif diff --git a/targets/esp32/components/VS1053/include/spectrum_analyzer.h b/targets/esp32/components/VS1053/include/spectrum_analyzer.h new file mode 100644 index 00000000..f163468f --- /dev/null +++ b/targets/esp32/components/VS1053/include/spectrum_analyzer.h @@ -0,0 +1,124 @@ + +const unsigned short PLUGIN[950] = { + /* Compressed plugin */ + 0x0007, 0x0001, 0x8050, 0x0006, 0x0018, 0x3613, 0x0024, 0x3e00, /* 0 */ + 0x3801, 0x0000, 0x16d7, 0xf400, 0x55c0, 0x0000, 0x0c17, 0xf400, /* 8 */ + 0x57c0, 0x0007, 0x9257, 0xb080, 0x0024, 0x3f00, 0x0024, 0x2000, /* 10 */ + 0x0000, 0x36f0, 0x1801, 0x2800, 0x31c0, 0x0007, 0x0001, 0x805c, /* 18 */ + 0x0006, 0x00d6, 0x3e12, 0xb817, 0x3e12, 0x3815, 0x3e05, 0xb814, /* 20 */ + 0x3615, 0x0024, 0x0000, 0x800a, 0x3e10, 0x3801, 0x0006, 0x0000, /* 28 */ + 0x3e10, 0xb803, 0x0000, 0x0303, 0x3e11, 0x3805, 0x3e11, 0xb807, /* 30 */ + 0x3e14, 0x3812, 0xb884, 0x130c, 0x3410, 0x4024, 0x4112, 0x10d0, /* 38 */ + 0x4010, 0x008c, 0x4010, 0x0024, 0xf400, 0x4012, 0x3000, 0x3840, /* 40 */ + 0x3009, 0x3801, 0x0000, 0x0041, 0xfe02, 0x0024, 0x2900, 0x8200, /* 48 */ + 0x48b2, 0x0024, 0x36f3, 0x0844, 0x6306, 0x8845, 0xae3a, 0x8840, /* 50 */ + 0xbf8e, 0x8b41, 0xac32, 0xa846, 0xffc8, 0xabc7, 0x3e01, 0x7800, /* 58 */ + 0xf400, 0x4480, 0x6090, 0x0024, 0x6090, 0x0024, 0xf400, 0x4015, /* 60 */ + 0x3009, 0x3446, 0x3009, 0x37c7, 0x3009, 0x1800, 0x3009, 0x3844, /* 68 */ + 0x48b3, 0xe1e0, 0x4882, 0x4040, 0xfeca, 0x0024, 0x5ac2, 0x0024, /* 70 */ + 0x5a52, 0x0024, 0x4cc2, 0x0024, 0x48ba, 0x4040, 0x4eea, 0x4801, /* 78 */ + 0x4eca, 0x9800, 0xff80, 0x1bc1, 0xf1eb, 0xe3e2, 0xf1ea, 0x184c, /* 80 */ + 0x4c8b, 0xe5e4, 0x48be, 0x9804, 0x488e, 0x41c6, 0xfe82, 0x0024, /* 88 */ + 0x5a8e, 0x0024, 0x525e, 0x1b85, 0x4ffe, 0x0024, 0x48b6, 0x41c6, /* 90 */ + 0x4dd6, 0x48c7, 0x4df6, 0x0024, 0xf1d6, 0x0024, 0xf1d6, 0x0024, /* 98 */ + 0x4eda, 0x0024, 0x0000, 0x0fc3, 0x2900, 0x8200, 0x4e82, 0x0024, /* a0 */ + 0x4084, 0x130c, 0x0006, 0x0100, 0x3440, 0x4024, 0x4010, 0x0024, /* a8 */ + 0xf400, 0x4012, 0x3200, 0x4024, 0xb132, 0x0024, 0x4214, 0x0024, /* b0 */ + 0xf224, 0x0024, 0x6230, 0x0024, 0x0001, 0x0001, 0x2800, 0x2b49, /* b8 */ + 0x0000, 0x0024, 0xf400, 0x40c2, 0x3200, 0x0024, 0xff82, 0x0024, /* c0 */ + 0x48b2, 0x0024, 0xb130, 0x0024, 0x6202, 0x0024, 0x003f, 0xf001, /* c8 */ + 0x2800, 0x2e51, 0x0000, 0x1046, 0xfe64, 0x0024, 0x48be, 0x0024, /* d0 */ + 0x2800, 0x2f40, 0x3a01, 0x8024, 0x3200, 0x0024, 0xb010, 0x0024, /* d8 */ + 0xc020, 0x0024, 0x3a00, 0x0024, 0x36f4, 0x1812, 0x36f1, 0x9807, /* e0 */ + 0x36f1, 0x1805, 0x36f0, 0x9803, 0x36f0, 0x1801, 0x3405, 0x9014, /* e8 */ + 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, 0x0000, 0x36f2, 0x9817, /* f0 */ + 0x0007, 0x0001, 0x80c7, 0x0006, 0x01ae, 0x3e12, 0xb817, 0x3e12, /* f8 */ + 0x3815, 0x3e05, 0xb814, 0x3625, 0x0024, 0x0000, 0x800a, 0x3e10, /* 100 */ + 0x7802, 0x3e10, 0xf804, 0x3e11, 0x7810, 0x3e14, 0x7813, 0x0006, /* 108 */ + 0x0051, 0x3e13, 0xf80e, 0x3e13, 0x4024, 0x3009, 0x3840, 0x3009, /* 110 */ + 0x3852, 0x2911, 0xf140, 0x0006, 0x06d0, 0x3100, 0x5bd2, 0x0006, /* 118 */ + 0xc351, 0x3009, 0x1bc0, 0x3009, 0x0402, 0x6126, 0x0024, 0x0006, /* 120 */ + 0x00d1, 0x2800, 0x4d45, 0x0000, 0x0024, 0x0006, 0x0011, 0xb882, /* 128 */ + 0x184c, 0x3009, 0x3850, 0x0006, 0x0010, 0x3009, 0x3800, 0x2914, /* 130 */ + 0xbec0, 0x0000, 0x1800, 0x0006, 0x0010, 0xb882, 0x0024, 0x2915, /* 138 */ + 0x7ac0, 0x0000, 0x1700, 0x0000, 0x0301, 0x3900, 0x5bc0, 0x0006, /* 140 */ + 0xc351, 0x3009, 0x1bd0, 0x3009, 0x0404, 0x0006, 0x0051, 0x2800, /* 148 */ + 0x3d40, 0x3901, 0x0024, 0x4448, 0x0401, 0x4192, 0x0024, 0x6498, /* 150 */ + 0x2401, 0x001f, 0x4001, 0x6412, 0x0024, 0x0006, 0x0011, 0x2800, /* 158 */ + 0x3c91, 0x0000, 0x058e, 0x2400, 0x4c4e, 0x0000, 0x0013, 0x0006, /* 160 */ + 0x0051, 0x0006, 0x1a03, 0x3100, 0x4024, 0xf212, 0x44c4, 0x4346, /* 168 */ + 0x0024, 0xf400, 0x40d5, 0x3500, 0x8024, 0x612a, 0x0024, 0x0000, /* 170 */ + 0x0024, 0x2800, 0x4c91, 0x0000, 0x0024, 0x3613, 0x0024, 0x3100, /* 178 */ + 0x3800, 0x2915, 0x7dc0, 0xf200, 0x0024, 0x003f, 0xfec2, 0x4082, /* 180 */ + 0x4411, 0x3113, 0x1bc0, 0xa122, 0x0024, 0x0000, 0x2002, 0x6124, /* 188 */ + 0x2401, 0x0000, 0x1002, 0x2800, 0x4648, 0x0000, 0x0024, 0x003f, /* 190 */ + 0xf802, 0x3100, 0x4024, 0xb124, 0x0024, 0x2800, 0x4c00, 0x3900, /* 198 */ + 0x8024, 0x6124, 0x0024, 0x0000, 0x0802, 0x2800, 0x4888, 0x0000, /* 1a0 */ + 0x0024, 0x003f, 0xfe02, 0x3100, 0x4024, 0xb124, 0x0024, 0x2800, /* 1a8 */ + 0x4c00, 0x3900, 0x8024, 0x6124, 0x0024, 0x0000, 0x0402, 0x2800, /* 1b0 */ + 0x4ac8, 0x0000, 0x0024, 0x003f, 0xff02, 0x3100, 0x4024, 0xb124, /* 1b8 */ + 0x0024, 0x2800, 0x4c00, 0x3900, 0x8024, 0x6124, 0x0401, 0x003f, /* 1c0 */ + 0xff82, 0x2800, 0x4c08, 0xb124, 0x0024, 0x3900, 0x8024, 0xb882, /* 1c8 */ + 0x8c4c, 0x3830, 0x4024, 0x0006, 0x0091, 0x3904, 0xc024, 0x0006, /* 1d0 */ + 0x00d1, 0x0000, 0x0013, 0x3100, 0x904c, 0x4202, 0x0024, 0x39f0, /* 1d8 */ + 0x4024, 0x3100, 0x4024, 0x3c00, 0x4024, 0xf400, 0x44c1, 0x34f0, /* 1e0 */ + 0x8024, 0x6126, 0x0024, 0x0006, 0x06d0, 0x2800, 0x5b98, 0x4294, /* 1e8 */ + 0x0024, 0x2400, 0x5b42, 0x0000, 0x0024, 0xf400, 0x4411, 0x3123, /* 1f0 */ + 0x0024, 0x3100, 0x8024, 0x4202, 0x0024, 0x4182, 0x2401, 0x0000, /* 1f8 */ + 0x2002, 0x2800, 0x5b49, 0x0000, 0x0024, 0x3013, 0x184c, 0x30f0, /* 200 */ + 0x7852, 0x6124, 0xb850, 0x0006, 0x0001, 0x2800, 0x55c8, 0x4088, /* 208 */ + 0x44c2, 0x4224, 0x0024, 0x4122, 0x0024, 0x4122, 0x0024, 0xf400, /* 210 */ + 0x4051, 0x2900, 0x7200, 0x0000, 0x5708, 0x4224, 0x0024, 0x4122, /* 218 */ + 0x0024, 0x4122, 0x0024, 0x2900, 0x6780, 0xf400, 0x4051, 0x0002, /* 220 */ + 0x0002, 0x3009, 0x1bd0, 0x3023, 0x1bd2, 0x30e0, 0x4024, 0x6124, /* 228 */ + 0x0024, 0x0000, 0x0024, 0x2800, 0x5b48, 0x0000, 0x0024, 0x3613, /* 230 */ + 0x0024, 0x3e14, 0xc024, 0x2900, 0x1700, 0x3e14, 0x0024, 0x36e3, /* 238 */ + 0x008c, 0x30e0, 0x8024, 0x6822, 0x4411, 0x3123, 0x0024, 0x3900, /* 240 */ + 0x4024, 0x3033, 0x0c4c, 0x0006, 0x0011, 0x6892, 0x04c2, 0xa122, /* 248 */ + 0x0402, 0x6126, 0x0024, 0x0006, 0x0093, 0x2800, 0x64c1, 0x0000, /* 250 */ + 0x0024, 0xb882, 0x184c, 0x3413, 0x3812, 0x0006, 0x00d2, 0x3a00, /* 258 */ + 0x5bd2, 0x3300, 0x4024, 0x0000, 0x0013, 0x3c00, 0x4024, 0xf400, /* 260 */ + 0x44c1, 0x34f0, 0x8024, 0x6126, 0x0024, 0x0006, 0x0111, 0x2800, /* 268 */ + 0x64d8, 0x4294, 0x0024, 0x2400, 0x6482, 0x0000, 0x0024, 0x0003, /* 270 */ + 0xf001, 0x3101, 0x0024, 0xb412, 0x0024, 0x0028, 0x0001, 0x2800, /* 278 */ + 0x6485, 0x6144, 0x0024, 0x0004, 0x0002, 0x2800, 0x6441, 0x4422, /* 280 */ + 0x0024, 0x0000, 0x1002, 0x6422, 0x0024, 0x2800, 0x6480, 0x3900, /* 288 */ + 0x4024, 0x3900, 0x4024, 0x3113, 0x0c4c, 0x36f3, 0x4024, 0x36f3, /* 290 */ + 0xd80e, 0x36f4, 0x5813, 0x36f1, 0x5810, 0x36f0, 0xd804, 0x36f0, /* 298 */ + 0x5802, 0x3405, 0x9014, 0x36f3, 0x0024, 0x36f2, 0x1815, 0x2000, /* 2a0 */ + 0x0000, 0x36f2, 0x9817, 0x0007, 0x0001, 0x1868, 0x0006, 0x000f, /* 2a8 */ + 0x0032, 0x004f, 0x007e, 0x00c8, 0x013d, 0x01f8, 0x0320, 0x04f6, /* 2b0 */ + 0x07e0, 0x0c80, 0x13d8, 0x1f7f, 0x3200, 0x4f5f, 0x61a8, 0x0006, /* 2b8 */ + 0x8008, 0x0000, 0x0007, 0x0001, 0x819e, 0x0006, 0x0054, 0x3e12, /* 2c0 */ + 0xb814, 0x0000, 0x800a, 0x3e10, 0x3801, 0x3e10, 0xb803, 0x3e11, /* 2c8 */ + 0x7806, 0x3e11, 0xf813, 0x3e13, 0xf80e, 0x3e13, 0x4024, 0x3e04, /* 2d0 */ + 0x7810, 0x449a, 0x0040, 0x0001, 0x0003, 0x2800, 0x70c4, 0x4036, /* 2d8 */ + 0x03c1, 0x0003, 0xffc2, 0xb326, 0x0024, 0x0018, 0x0042, 0x4326, /* 2e0 */ + 0x4495, 0x4024, 0x40d2, 0x0000, 0x0180, 0xa100, 0x4090, 0x0010, /* 2e8 */ + 0x0fc2, 0x4204, 0x0024, 0xbc82, 0x4091, 0x459a, 0x0024, 0x0000, /* 2f0 */ + 0x0054, 0x2800, 0x6fc4, 0xbd86, 0x4093, 0x2400, 0x6f85, 0xfe01, /* 2f8 */ + 0x5e0c, 0x5c43, 0x5f2d, 0x5e46, 0x020c, 0x5c56, 0x8a0c, 0x5e53, /* 300 */ + 0x5e0c, 0x5c43, 0x5f2d, 0x5e46, 0x020c, 0x5c56, 0x8a0c, 0x5e52, /* 308 */ + 0x0024, 0x4cb2, 0x4405, 0x0018, 0x0044, 0x654a, 0x0024, 0x2800, /* 310 */ + 0x7dc0, 0x36f4, 0x5810, 0x0007, 0x0001, 0x81c8, 0x0006, 0x0080, /* 318 */ + 0x3e12, 0xb814, 0x0000, 0x800a, 0x3e10, 0x3801, 0x3e10, 0xb803, /* 320 */ + 0x3e11, 0x7806, 0x3e11, 0xf813, 0x3e13, 0xf80e, 0x3e13, 0x4024, /* 328 */ + 0x3e04, 0x7810, 0x449a, 0x0040, 0x0000, 0x0803, 0x2800, 0x7c84, /* 330 */ + 0x30f0, 0x4024, 0x0fff, 0xfec2, 0xa020, 0x0024, 0x0fff, 0xff02, /* 338 */ + 0xa122, 0x0024, 0x4036, 0x0024, 0x0000, 0x1fc2, 0xb326, 0x0024, /* 340 */ + 0x0010, 0x4002, 0x4326, 0x4495, 0x4024, 0x40d2, 0x0000, 0x0180, /* 348 */ + 0xa100, 0x4090, 0x0010, 0x0042, 0x4204, 0x0024, 0xbc82, 0x4091, /* 350 */ + 0x459a, 0x0024, 0x0000, 0x0054, 0x2800, 0x7b84, 0xbd86, 0x4093, /* 358 */ + 0x2400, 0x7b45, 0xfe01, 0x5e0c, 0x5c43, 0x5f2d, 0x5e46, 0x0024, /* 360 */ + 0x5c56, 0x0024, 0x5e53, 0x5e0c, 0x5c43, 0x5f2d, 0x5e46, 0x0024, /* 368 */ + 0x5c56, 0x0024, 0x5e52, 0x0024, 0x4cb2, 0x4405, 0x0010, 0x4004, /* 370 */ + 0x654a, 0x9810, 0x0000, 0x0144, 0xa54a, 0x1bd1, 0x0006, 0x0013, /* 378 */ + 0x3301, 0xc444, 0x687e, 0x2005, 0xad76, 0x8445, 0x4ed6, 0x8784, /* 380 */ + 0x36f3, 0x64c2, 0xac72, 0x8785, 0x4ec2, 0xa443, 0x3009, 0x2440, /* 388 */ + 0x3009, 0x2741, 0x36f3, 0xd80e, 0x36f1, 0xd813, 0x36f1, 0x5806, /* 390 */ + 0x36f0, 0x9803, 0x36f0, 0x1801, 0x2000, 0x0000, 0x36f2, 0x9814, /* 398 */ + 0x0007, 0x0001, 0x8208, 0x0006, 0x000e, 0x4c82, 0x0024, 0x0000, /* 3a0 */ + 0x0024, 0x2000, 0x0005, 0xf5c2, 0x0024, 0x0000, 0x0980, 0x2000, /* 3a8 */ + 0x0000, 0x6010, 0x0024, 0x000a, 0x0001, 0x0050, +#define PLUGIN_SIZE 950 +}; diff --git a/targets/esp32/components/VS1053/include/vs10xx_uc.h b/targets/esp32/components/VS1053/include/vs10xx_uc.h new file mode 100644 index 00000000..b310fca9 --- /dev/null +++ b/targets/esp32/components/VS1053/include/vs10xx_uc.h @@ -0,0 +1,561 @@ +#ifndef VS10XX_MICROCONTROLLER_DEFINITIONS_H +#define VS10XX_MICROCONTROLLER_DEFINITIONS_H + +/* + + VLSI Solution microcontroller definitions for: + VS1063, VS1053 (and VS8053), VS1033, VS1003, VS1103, VS1011. + + v1.01 2012-11-26 HH Added VS1053 recording registers, bug fixes + v1.00 2012-11-23 HH Initial version + +*/ + + + + + +/* SCI registers */ +#define SCI_num_registers 0x0f +#define VS_WRITE_COMMAND 0x02 +#define VS_READ_COMMAND 0x03 + +#define SCI_MODE 0x00 +#define SCI_STATUS 0x01 +#define SCI_BASS 0x02 +#define SCI_CLOCKF 0x03 +#define SCI_DECODE_TIME 0x04 +#define SCI_AUDATA 0x05 +#define SCI_WRAM 0x06 +#define SCI_WRAMADDR 0x07 +#define SCI_HDAT0 0x08 /* VS1063, VS1053, VS1033, VS1003, VS1011 */ +#define SCI_IN0 0x08 /* VS1103 */ +#define SCI_HDAT1 0x09 /* VS1063, VS1053, VS1033, VS1003, VS1011 */ +#define SCI_IN1 0x09 /* VS1103 */ +#define SCI_AIADDR 0x0A +#define SCI_VOL 0x0B +#define SCI_AICTRL0 0x0C /* VS1063, VS1053, VS1033, VS1003, VS1011 */ +#define SCI_MIXERVOL 0x0C /* VS1103 */ +#define SCI_AICTRL1 0x0D /* VS1063, VS1053, VS1033, VS1003, VS1011 */ +#define SCI_ADPCMRECCTL 0x0D /* VS1103 */ +#define SCI_AICTRL2 0x0E +#define SCI_AICTRL3 0x0F + + +/* SCI register recording aliases */ + +#define SCI_RECQUALITY 0x07 /* (WRAMADDR) VS1063 */ +#define SCI_RECDATA 0x08 /* (HDAT0) VS1063 */ +#define SCI_RECWORDS 0x09 /* (HDAT1) VS1063 */ +#define SCI_RECRATE 0x0C /* (AICTRL0) VS1063, VS1053 */ +#define SCI_RECDIV 0x0C /* (AICTRL0) VS1033, VS1003 */ +#define SCI_RECGAIN 0x0D /* (AICTRL1) VS1063, VS1053, VS1033, VS1003 */ +#define SCI_RECMAXAUTO 0x0E /* (AICTRL2) VS1063, VS1053, VS1033 */ +#define SCI_RECMODE 0x0F /* (AICTRL3) VS1063, VS1053 */ + + +/* SCI_MODE bits */ + +#define SM_DIFF_B 0 +#define SM_LAYER12_B 1 /* VS1063, VS1053, VS1033, VS1011 */ +#define SM_RECORD_PATH_B 1 /* VS1103 */ +#define SM_RESET_B 2 +#define SM_CANCEL_B 3 /* VS1063, VS1053 */ +#define SM_OUTOFWAV_B 3 /* VS1033, VS1003, VS1011 */ +#define SM_OUTOFMIDI_B 3 /* VS1103 */ +#define SM_EARSPEAKER_LO_B 4 /* VS1053, VS1033 */ +#define SM_PDOWN_B 4 /* VS1003, VS1103 */ +#define SM_TESTS_B 5 +#define SM_STREAM_B 6 /* VS1053, VS1033, VS1003, VS1011 */ +#define SM_ICONF_B 6 /* VS1103 */ +#define SM_EARSPEAKER_HI_B 7 /* VS1053, VS1033 */ +#define SM_DACT_B 8 +#define SM_SDIORD_B 9 +#define SM_SDISHARE_B 10 +#define SM_SDINEW_B 11 +#define SM_ENCODE_B 12 /* VS1063 */ +#define SM_ADPCM_B 12 /* VS1053, VS1033, VS1003 */ +#define SM_EARSPEAKER_1103_B 12 /* VS1103 */ +#define SM_ADPCM_HP_B 13 /* VS1033, VS1003 */ +#define SM_LINE1_B 14 /* VS1063, VS1053 */ +#define SM_LINE_IN_B 14 /* VS1033, VS1003, VS1103 */ +#define SM_CLK_RANGE_B 15 /* VS1063, VS1053, VS1033 */ +#define SM_ADPCM_1103_B 15 /* VS1103 */ + +#define SM_DIFF (1<< 0) +#define SM_LAYER12 (1<< 1) /* VS1063, VS1053, VS1033, VS1011 */ +#define SM_RECORD_PATH (1<< 1) /* VS1103 */ +#define SM_RESET (1<< 2) +#define SM_CANCEL (1<< 3) /* VS1063, VS1053 */ +#define SM_OUTOFWAV (1<< 3) /* VS1033, VS1003, VS1011 */ +#define SM_OUTOFMIDI (1<< 3) /* VS1103 */ +#define SM_EARSPEAKER_LO (1<< 4) /* VS1053, VS1033 */ +#define SM_PDOWN (1<< 4) /* VS1003, VS1103 */ +#define SM_TESTS (1<< 5) +#define SM_STREAM (1<< 6) /* VS1053, VS1033, VS1003, VS1011 */ +#define SM_ICONF (1<< 6) /* VS1103 */ +#define SM_EARSPEAKER_HI (1<< 7) /* VS1053, VS1033 */ +#define SM_DACT (1<< 8) +#define SM_SDIORD (1<< 9) +#define SM_SDISHARE (1<<10) +#define SM_SDINEW (1<<11) +#define SM_ENCODE (1<<12) /* VS1063 */ +#define SM_ADPCM (1<<12) /* VS1053, VS1033, VS1003 */ +#define SM_EARSPEAKER1103 (1<<12) /* VS1103 */ +#define SM_ADPCM_HP (1<<13) /* VS1033, VS1003 */ +#define SM_LINE1 (1<<14) /* VS1063, VS1053 */ +#define SM_LINE_IN (1<<14) /* VS1033, VS1003, VS1103 */ +#define SM_CLK_RANGE (1<<15) /* VS1063, VS1053, VS1033 */ +#define SM_ADPCM_1103 (1<<15) /* VS1103 */ + +#define SM_ICONF_BITS 2 +#define SM_ICONF_MASK 0x00c0 + +#define SM_EARSPEAKER_1103_BITS 2 +#define SM_EARSPEAKER_1103_MASK 0x3000 + + +/* SCI_STATUS bits */ + +#define SS_REFERENCE_SEL_B 0 /* VS1063, VS1053 */ +#define SS_AVOL_B 0 /* VS1033, VS1003, VS1103, VS1011 */ +#define SS_AD_CLOCK_B 1 /* VS1063, VS1053 */ +#define SS_APDOWN1_B 2 +#define SS_APDOWN2_B 3 +#define SS_VER_B 4 +#define SS_VCM_DISABLE_B 10 /* VS1063, VS1053 */ +#define SS_VCM_OVERLOAD_B 11 /* VS1063, VS1053 */ +#define SS_SWING_B 12 /* VS1063, VS1053 */ +#define SS_DO_NOT_JUMP_B 15 /* VS1063, VS1053 */ + +#define SS_REFERENCE_SEL (1<< 0) /* VS1063, VS1053 */ +#define SS_AVOL (1<< 0) /* VS1033, VS1003, VS1103, VS1011 */ +#define SS_AD_CLOCK (1<< 1) /* VS1063, VS1053 */ +#define SS_APDOWN1 (1<< 2) +#define SS_APDOWN2 (1<< 3) +#define SS_VER (1<< 4) +#define SS_VCM_DISABLE (1<<10) /* VS1063, VS1053 */ +#define SS_VCM_OVERLOAD (1<<11) /* VS1063, VS1053 */ +#define SS_SWING (1<<12) /* VS1063, VS1053 */ +#define SS_DO_NOT_JUMP (1<<15) /* VS1063, VS1053 */ + +#define SS_SWING_BITS 3 +#define SS_SWING_MASK 0x7000 +#define SS_VER_BITS 4 +#define SS_VER_MASK 0x00f0 +#define SS_AVOL_BITS 2 +#define SS_AVOL_MASK 0x0003 + +#define SS_VER_VS1001 0x00 +#define SS_VER_VS1011 0x10 +#define SS_VER_VS1002 0x20 +#define SS_VER_VS1003 0x30 +#define SS_VER_VS1053 0x40 +#define SS_VER_VS8053 0x40 +#define SS_VER_VS1033 0x50 +#define SS_VER_VS1063 0x60 +#define SS_VER_VS1103 0x70 + + +/* SCI_BASS bits */ + +#define ST_AMPLITUDE_B 12 +#define ST_FREQLIMIT_B 8 +#define SB_AMPLITUDE_B 4 +#define SB_FREQLIMIT_B 0 + +#define ST_AMPLITUDE (1<<12) +#define ST_FREQLIMIT (1<< 8) +#define SB_AMPLITUDE (1<< 4) +#define SB_FREQLIMIT (1<< 0) + +#define ST_AMPLITUDE_BITS 4 +#define ST_AMPLITUDE_MASK 0xf000 +#define ST_FREQLIMIT_BITS 4 +#define ST_FREQLIMIT_MASK 0x0f00 +#define SB_AMPLITUDE_BITS 4 +#define SB_AMPLITUDE_MASK 0x00f0 +#define SB_FREQLIMIT_BITS 4 +#define SB_FREQLIMIT_MASK 0x000f + + +/* SCI_CLOCKF bits */ + +#define SC_MULT_B 13 /* VS1063, VS1053, VS1033, VS1103, VS1003 */ +#define SC_ADD_B 11 /* VS1063, VS1053, VS1033, VS1003 */ +#define SC_FREQ_B 0 /* VS1063, VS1053, VS1033, VS1103, VS1003 */ + +#define SC_MULT (1<<13) /* VS1063, VS1053, VS1033, VS1103, VS1003 */ +#define SC_ADD (1<<11) /* VS1063, VS1053, VS1033, VS1003 */ +#define SC_FREQ (1<< 0) /* VS1063, VS1053, VS1033, VS1103, VS1003 */ + +#define SC_MULT_BITS 3 +#define SC_MULT_MASK 0xe000 +#define SC_ADD_BITS 2 +#define SC_ADD_MASK 0x1800 +#define SC_FREQ_BITS 11 +#define SC_FREQ_MASK 0x07ff + +/* The following macro is for VS1063, VS1053, VS1033, VS1003, VS1103. + Divide hz by two when calling if SM_CLK_RANGE = 1 */ +#define HZ_TO_SC_FREQ(hz) (((hz)-8000000+2000)/4000) + +/* The following macro is for VS1011. + The macro will automatically set the clock doubler if XTALI < 16 MHz */ +#define HZ_TO_SCI_CLOCKF(hz) ((((hz)<16000000)?0x8000:0)+((hz)+1000)/2000) + +/* Following are for VS1003 and VS1033 */ +#define SC_MULT_03_10X 0x0000 +#define SC_MULT_03_15X 0x2000 +#define SC_MULT_03_20X 0x4000 +#define SC_MULT_03_25X 0x6000 +#define SC_MULT_03_30X 0x8000 +#define SC_MULT_03_35X 0xa000 +#define SC_MULT_03_40X 0xc000 +#define SC_MULT_03_45X 0xe000 + +/* Following are for VS1053 and VS1063 */ +#define SC_MULT_53_10X 0x0000 +#define SC_MULT_53_20X 0x2000 +#define SC_MULT_53_25X 0x4000 +#define SC_MULT_53_30X 0x6000 +#define SC_MULT_53_35X 0x8000 +#define SC_MULT_53_40X 0xa000 +#define SC_MULT_53_45X 0xc000 +#define SC_MULT_53_50X 0xe000 + +/* Following are for VS1003 and VS1033 */ +#define SC_ADD_03_00X 0x0000 +#define SC_ADD_03_05X 0x0800 +#define SC_ADD_03_10X 0x1000 +#define SC_ADD_03_15X 0x1800 + +/* Following are for VS1053 and VS1063 */ +#define SC_ADD_53_00X 0x0000 +#define SC_ADD_53_10X 0x0800 +#define SC_ADD_53_15X 0x1000 +#define SC_ADD_53_20X 0x1800 + + +/* SCI_WRAMADDR bits */ + +#define SCI_WRAM_X_START 0x0000 +#define SCI_WRAM_Y_START 0x4000 +#define SCI_WRAM_I_START 0x8000 +#define SCI_WRAM_IO_START 0xC000 +#define SCI_WRAM_PARAMETRIC_START 0xC0C0 /* VS1063 */ +#define SCI_WRAM_Y2_START 0xE000 /* VS1063 */ + +#define SCI_WRAM_X_OFFSET 0x0000 +#define SCI_WRAM_Y_OFFSET 0x4000 +#define SCI_WRAM_I_OFFSET 0x8000 +#define SCI_WRAM_IO_OFFSET 0x0000 /* I/O addresses are @0xC000 -> no offset */ +#define SCI_WRAM_PARAMETRIC_OFFSET (0xC0C0-0x1E00) /* VS1063 */ +#define SCI_WRAM_Y2_OFFSET 0x0000 /* VS1063 */ + + +/* SCI_VOL bits */ + +#define SV_LEFT_B 8 +#define SV_RIGHT_B 0 + +#define SV_LEFT (1<<8) +#define SV_RIGHT (1<<0) + +#define SV_LEFT_BITS 8 +#define SV_LEFT_MASK 0xFF00 +#define SV_RIGHT_BITS 8 +#define SV_RIGHT_MASK 0x00FF + + +/* SCI_MIXERVOL bits for VS1103 */ + +#define SMV_ACTIVE_B 15 +#define SMV_GAIN3_B 10 +#define SMV_GAIN2_B 5 +#define SMV_GAIN1_B 0 + +#define SMV_ACTIVE (1<<15) +#define SMV_GAIN3 (1<<10) +#define SMV_GAIN2 (1<< 5) +#define SMV_GAIN1 (1<< 0) + +#define SMV_GAIN3_BITS 5 +#define SMV_GAIN3_MASK 0x7c00 +#define SMV_GAIN2_BITS 5 +#define SMV_GAIN2_MASK 0x04e0 +#define SMV_GAIN1_BITS 5 +#define SMV_GAIN1_MASK 0x001f + + +/* SCI_ADPCMRECCTL bits for VS1103 */ + +#define SARC_DREQ512_B 8 +#define SARC_OUTODADPCM_B 7 +#define SARC_MANUALGAIN_B 6 +#define SARC_GAIN4_B 0 + +#define SARC_DREQ512 (1<<8) +#define SARC_OUTODADPCM (1<<7) +#define SARC_MANUALGAIN (1<<6) +#define SARC_GAIN4 (1<<0) + +#define SARC_GAIN4_BITS 6 +#define SARC_GAIN4_MASK 0x003f + + +/* SCI_RECQUALITY bits for VS1063 */ + +#define RQ_MODE_B 14 +#define RQ_MULT_B 12 +#define RQ_OGG_PAR_SERIAL_NUMBER_B 11 +#define RQ_OGG_LIMIT_FRAME_LENGTH_B 10 +#define RQ_MP3_NO_BIT_RESERVOIR_B 10 +#define RQ_BITRATE_BASE_B 0 + +#define RQ_MODE (1<<14) +#define RQ_MULT (1<<12) +#define RQ_OGG_PAR_SERIAL_NUMBER (1<<11) +#define RQ_OGG_LIMIT_FRAME_LENGTH (1<<10) +#define RQ_MP3_NO_BIT_RESERVOIR (1<<10) +#define RQ_BITRATE_BASE (1<< 0) + +#define RQ_MODE_BITS 2 +#define RQ_MODE_MASK 0xc000 +#define RQ_MULT_BITS 2 +#define RQ_MULT_MASK 0x3000 +#define RQ_BITRATE_BASE_BITS 9 +#define RQ_BITRATE_BASE_MASK 0x01ff + +#define RQ_MODE_QUALITY 0x0000 +#define RQ_MODE_VBR 0x4000 +#define RQ_MODE_ABR 0x8000 +#define RQ_MODE_CBR 0xc000 + +#define RQ_MULT_10 0x0000 +#define RQ_MULT_100 0x1000 +#define RQ_MULT_1000 0x2000 +#define RQ_MULT_10000 0x3000 + + +/* SCI_RECMODE bits for VS1063 */ + +#define RM_63_CODEC_B 15 +#define RM_63_AEC_B 14 +#define RM_63_UART_TX_B 13 +#define RM_63_PAUSE_B 11 +#define RM_63_NO_RIFF_B 10 +#define RM_63_FORMAT_B 4 +#define RM_63_ADC_MODE_B 0 + +#define RM_63_CODEC (1<<15) +#define RM_63_AEC (1<<14) +#define RM_63_UART_TX (1<<13) +#define RM_63_PAUSE (1<<11) +#define RM_63_NO_RIFF (1<<10) +#define RM_63_FORMAT (1<< 4) +#define RM_63_ADC_MODE (1<< 0) + +#define RM_63_FORMAT_BITS 4 +#define RM_63_FORMAT_MASK 0x00f0 +#define RM_63_ADCMODE_BITS 3 +#define RM_63_ADCMODE_MASK 0x0007 + +#define RM_63_FORMAT_IMA_ADPCM 0x0000 +#define RM_63_FORMAT_PCM 0x0010 +#define RM_63_FORMAT_G711_ULAW 0x0020 +#define RM_63_FORMAT_G711_ALAW 0x0030 +#define RM_63_FORMAT_G722_ADPCM 0x0040 +#define RM_63_FORMAT_OGG_VORBIS 0x0050 +#define RM_63_FORMAT_MP3 0x0060 + +#define RM_63_ADC_MODE_JOINT_AGC_STEREO 0x0000 +#define RM_63_ADC_MODE_DUAL_AGC_STEREO 0x0001 +#define RM_63_ADC_MODE_LEFT 0x0002 +#define RM_63_ADC_MODE_RIGHT 0x0003 +#define RM_63_ADC_MODE_MONO 0x0004 + + +/* SCI_RECMODE bits for VS1053 */ + +#define RM_53_FORMAT_B 2 +#define RM_53_ADC_MODE_B 0 + +#define RM_53_FORMAT (1<< 2) +#define RM_53_ADC_MODE (1<< 0) + +#define RM_53_ADCMODE_BITS 2 +#define RM_53_ADCMODE_MASK 0x0003 + +#define RM_53_FORMAT_IMA_ADPCM 0x0000 +#define RM_53_FORMAT_PCM 0x0004 + +#define RM_53_ADC_MODE_JOINT_AGC_STEREO 0x0000 +#define RM_53_ADC_MODE_DUAL_AGC_STEREO 0x0001 +#define RM_53_ADC_MODE_LEFT 0x0002 +#define RM_53_ADC_MODE_RIGHT 0x0003 + + +/* VS1063 definitions */ + +/* VS1063 / VS1053 Parametric */ +#define PAR_CHIP_ID 0x1e00 /* VS1063, VS1053, 32 bits */ +#define PAR_VERSION 0x1e02 /* VS1063, VS1053 */ +#define PAR_CONFIG1 0x1e03 /* VS1063, VS1053 */ +#define PAR_PLAY_SPEED 0x1e04 /* VS1063, VS1053 */ +#define PAR_BITRATE_PER_100 0x1e05 /* VS1063 */ +#define PAR_BYTERATE 0x1e05 /* VS1053 */ +#define PAR_END_FILL_BYTE 0x1e06 /* VS1063, VS1053 */ +#define PAR_RATE_TUNE 0x1e07 /* VS1063, 32 bits */ +#define PAR_PLAY_MODE 0x1e09 /* VS1063 */ +#define PAR_SAMPLE_COUNTER 0x1e0a /* VS1063, 32 bits */ +#define PAR_VU_METER 0x1e0c /* VS1063 */ +#define PAR_AD_MIXER_GAIN 0x1e0d /* VS1063 */ +#define PAR_AD_MIXER_CONFIG 0x1e0e /* VS1063 */ +#define PAR_PCM_MIXER_RATE 0x1e0f /* VS1063 */ +#define PAR_PCM_MIXER_FREE 0x1e10 /* VS1063 */ +#define PAR_PCM_MIXER_VOL 0x1e11 /* VS1063 */ +#define PAR_EQ5_DUMMY 0x1e12 /* VS1063 */ +#define PAR_EQ5_LEVEL1 0x1e13 /* VS1063 */ +#define PAR_EQ5_FREQ1 0x1e14 /* VS1063 */ +#define PAR_EQ5_LEVEL2 0x1e15 /* VS1063 */ +#define PAR_EQ5_FREQ2 0x1e16 /* VS1063 */ +#define PAR_JUMP_POINTS 0x1e16 /* VS1053 */ +#define PAR_EQ5_LEVEL3 0x1e17 /* VS1063 */ +#define PAR_EQ5_FREQ3 0x1e18 /* VS1063 */ +#define PAR_EQ5_LEVEL4 0x1e19 /* VS1063 */ +#define PAR_EQ5_FREQ4 0x1e1a /* VS1063 */ +#define PAR_EQ5_LEVEL5 0x1e1b /* VS1063 */ +#define PAR_EQ5_UPDATED 0x1e1c /* VS1063 */ +#define PAR_SPEED_SHIFTER 0x1e1d /* VS1063 */ +#define PAR_EARSPEAKER_LEVEL 0x1e1e /* VS1063 */ +#define PAR_SDI_FREE 0x1e1f /* VS1063 */ +#define PAR_AUDIO_FILL 0x1e20 /* VS1063 */ +#define PAR_RESERVED0 0x1e21 /* VS1063 */ +#define PAR_RESERVED1 0x1e22 /* VS1063 */ +#define PAR_RESERVED2 0x1e23 /* VS1063 */ +#define PAR_RESERVED3 0x1e24 /* VS1063 */ +#define PAR_LATEST_SOF 0x1e25 /* VS1063, 32 bits */ +#define PAR_LATEST_JUMP 0x1e26 /* VS1053 */ +#define PAR_POSITION_MSEC 0x1e27 /* VS1063, VS1053, 32 bits */ +#define PAR_RESYNC 0x1e29 /* VS1063, VS1053 */ + +/* The following addresses are shared between modes. */ +/* Generic pointer */ +#define PAR_GENERIC 0x1e2a /* VS1063, VS1053 */ + +/* Encoder mode */ +#define PAR_ENC_TX_UART_DIV 0x1e2a /* VS1063 */ +#define PAR_ENC_TX_UART_BYTE_SPEED 0x1e2b /* VS1063 */ +#define PAR_ENC_TX_PAUSE_GPIO 0x1e2c /* VS1063 */ +#define PAR_ENC_AEC_ADAPT_MULTIPLIER 0x1e2d /* VS1063 */ +#define PAR_ENC_RESERVED 0x1e2e /* VS1063 */ +#define PAR_ENC_CHANNEL_MAX 0x1e3c /* VS1063 */ +#define PAR_ENC_SERIAL_NUMBER 0x1e3e /* VS1063 */ + +/* Decoding WMA */ +#define PAR_WMA_CUR_PACKET_SIZE 0x1e2a /* VS1063, VS1053, 32 bits */ +#define PAR_WMA_PACKET_SIZE 0x1e2c /* VS1063, VS1053, 32 bits */ + +/* Decoding AAC */ +#define PAR_AAC_SCE_FOUND_MASK 0x1e2a /* VS1063, VS1053 */ +#define PAR_AAC_CPE_FOUND_MASK 0x1e2b /* VS1063, VS1053 */ +#define PAR_AAC_LFE_FOUND_MASK 0x1e2c /* VS1063, VS1053 */ +#define PAR_AAC_PLAY_SELECT 0x1e2d /* VS1063, VS1053 */ +#define PAR_AAC_DYN_COMPRESS 0x1e2e /* VS1063, VS1053 */ +#define PAR_AAC_DYN_BOOST 0x1e2f /* VS1063, VS1053 */ +#define PAR_AAC_SBR_AND_PS_STATUS 0x1e30 /* VS1063, VS1053 */ +#define PAR_AAC_SBR_PS_FLAGS 0x1e31 /* VS1063 */ + + +/* Decoding MIDI (VS1053) */ +#define PAR_MIDI_BYTES_LEFT 0x1e2a /* VS1053, 32 bits */ + +/* Decoding Vorbis */ +#define PAR_VORBIS_GAIN 0x1e2a 0x1e30 /* VS1063, VS1053 */ + + +/* Bit definitions for parametric registers with bitfields */ +#define PAR_CONFIG1_DIS_WMA_B 15 /* VS1063 */ +#define PAR_CONFIG1_DIS_AAC_B 14 /* VS1063 */ +#define PAR_CONFIG1_DIS_MP3_B 13 /* VS1063 */ +#define PAR_CONFIG1_DIS_FLAC_B 12 /* VS1063 */ +#define PAR_CONFIG1_DIS_CRC_B 8 /* VS1063 */ +#define PAR_CONFIG1_AAC_PS_B 6 /* VS1063, VS1053 */ +#define PAR_CONFIG1_AAC_SBR_B 4 /* VS1063, VS1053 */ +#define PAR_CONFIG1_MIDI_REVERB_B 0 /* VS1053 */ + +#define PAR_CONFIG1_DIS_WMA (1<<15) /* VS1063 */ +#define PAR_CONFIG1_DIS_AAC (1<<14) /* VS1063 */ +#define PAR_CONFIG1_DIS_MP3 (1<<13) /* VS1063 */ +#define PAR_CONFIG1_DIS_FLAC (1<<12) /* VS1063 */ +#define PAR_CONFIG1_DIS_CRC (1<< 8) /* VS1063 */ +#define PAR_CONFIG1_AAC_PS (1<< 6) /* VS1063, VS1053 */ +#define PAR_CONFIG1_AAC_SBR (1<< 4) /* VS1063, VS1053 */ +#define PAR_CONFIG1_MIDI_REVERB (1<< 0) /* VS1053 */ + +#define PAR_CONFIG1_AAC_PS_BITS 2 /* VS1063, VS1053 */ +#define PAR_CONFIG1_AAC_PS_MASK 0x00c0 /* VS1063, VS1053 */ +#define PAR_CONFIG1_AAC_SBR_BITS 2 /* VS1063, VS1053 */ +#define PAR_CONFIG1_AAC_SBR_MASK 0x0030 /* VS1063, VS1053 */ + +#define PAR_CONFIG1_AAC_SBR_ALWAYS_UPSAMPLE 0x0000 /* VS1063, VS1053 */ +#define PAR_CONFIG1_AAC_SBR_SELECTIVE_UPSAMPLE 0x0010 /* VS1063, VS1053 */ +#define PAR_CONFIG1_AAC_SBR_NEVER_UPSAMPLE 0x0020 /* VS1063, VS1053 */ +#define PAR_CONFIG1_AAC_SBR_DISABLE 0x0030 /* VS1063, VS1053 */ + +#define PAR_CONFIG1_AAC_PS_NORMAL 0x0000 /* VS1063, VS1053 */ +#define PAR_CONFIG1_AAC_PS_DOWNSAMPLED 0x0040 /* VS1063, VS1053 */ +#define PAR_CONFIG1_AAC_PS_DISABLE 0x00c0 /* VS1063, VS1053 */ + +#define PAR_PLAY_MODE_SPEED_SHIFTER_ENA_B 6 /* VS1063 */ +#define PAR_PLAY_MODE_EQ5_ENA_B 5 /* VS1063 */ +#define PAR_PLAY_MODE_PCM_MIXER_ENA_B 4 /* VS1063 */ +#define PAR_PLAY_MODE_AD_MIXER_ENA_B 3 /* VS1063 */ +#define PAR_PLAY_MODE_VU_METER_ENA_B 2 /* VS1063 */ +#define PAR_PLAY_MODE_PAUSE_ENA_B 1 /* VS1063 */ +#define PAR_PLAY_MODE_MONO_ENA_B 0 /* VS1063 */ + +#define PAR_PLAY_MODE_SPEED_SHIFTER_ENA (1<<6) /* VS1063 */ +#define PAR_PLAY_MODE_EQ5_ENA (1<<5) /* VS1063 */ +#define PAR_PLAY_MODE_PCM_MIXER_ENA (1<<4) /* VS1063 */ +#define PAR_PLAY_MODE_AD_MIXER_ENA (1<<3) /* VS1063 */ +#define PAR_PLAY_MODE_VU_METER_ENA (1<<2) /* VS1063 */ +#define PAR_PLAY_MODE_PAUSE_ENA (1<<1) /* VS1063 */ +#define PAR_PLAY_MODE_MONO_ENA (1<<0) /* VS1063 */ + +#define PAR_VU_METER_LEFT_BITS 8 /* VS1063 */ +#define PAR_VU_METER_LEFT_MASK 0xFF00 /* VS1063 */ +#define PAR_VU_METER_RIGHT_BITS 8 /* VS1063 */ +#define PAR_VU_METER_RIGHT_MASK 0x00FF /* VS1063 */ + +#define PAR_AD_MIXER_CONFIG_MODE_B 2 /* VS1063 */ +#define PAR_AD_MIXER_CONFIG_RATE_B 2 /* VS1063 */ + +#define PAR_AD_MIXER_CONFIG_MODE_BITS 2 /* VS1063 */ +#define PAR_AD_MIXER_CONFIG_MODE_MASK 0x000c /* VS1063 */ +#define PAR_AD_MIXER_CONFIG_RATE_BITS 2 /* VS1063 */ +#define PAR_AD_MIXER_CONFIG_RATE_MASK 0x0003 /* VS1063 */ + +#define PAR_AD_MIXER_CONFIG_RATE_192K 0x0000 /* VS1063 */ +#define PAR_AD_MIXER_CONFIG_RATE_96K 0x0001 /* VS1063 */ +#define PAR_AD_MIXER_CONFIG_RATE_48K 0x0002 /* VS1063 */ +#define PAR_AD_MIXER_CONFIG_RATE_24K 0x0003 /* VS1063 */ + +#define PAR_AD_MIXER_CONFIG_MODE_STEREO 0x0000 /* VS1063 */ +#define PAR_AD_MIXER_CONFIG_MODE_MONO 0x0040 /* VS1063 */ +#define PAR_AD_MIXER_CONFIG_MODE_LEFT 0x0080 /* VS1063 */ +#define PAR_AD_MIXER_CONFIG_MODE_RIGHT 0x00c0 /* VS1063 */ + +#define PAR_AAC_SBR_AND_PS_STATUS_SBR_PRESENT_B 0 /* VS1063, VS1053 */ +#define PAR_AAC_SBR_AND_PS_STATUS_UPSAMPLING_ACTIVE_B 1 /* VS1063, VS1053 */ +#define PAR_AAC_SBR_AND_PS_STATUS_PS_PRESENT_B 2 /* VS1063, VS1053 */ +#define PAR_AAC_SBR_AND_PS_STATUS_PS_ACTIVE_B 3 /* VS1063, VS1053 */ + +#define PAR_AAC_SBR_AND_PS_STATUS_SBR_PRESENT (1<<0) /* VS1063, VS1053 */ +#define PAR_AAC_SBR_AND_PS_STATUS_UPSAMPLING_ACTIVE (1<<1) /* VS1063, VS1053 */ +#define PAR_AAC_SBR_AND_PS_STATUS_PS_PRESENT (1<<2) /* VS1063, VS1053 */ +#define PAR_AAC_SBR_AND_PS_STATUS_PS_ACTIVE (1<<3) /* VS1063, VS1053 */ + + +#endif /* !VS10XX_MICROCONTROLLER_DEFINITIONS_H */ diff --git a/targets/esp32/components/VS1053/src/VS1053.cpp b/targets/esp32/components/VS1053/src/VS1053.cpp new file mode 100644 index 00000000..bf9151f4 --- /dev/null +++ b/targets/esp32/components/VS1053/src/VS1053.cpp @@ -0,0 +1,669 @@ +#include "VS1053.h" + +#include +#include "BellLogger.h" + +static const char* TAG = "VS_SINK"; +void vs_feed(void* sink) { + ((VS1053_SINK*)sink)->run_feed(1024); +} + +unsigned char pcm_wav_header[44] = { + 0x52, 0x49, 0x46, + 0x46, // RIFF + 0xFF, 0xFF, 0xFF, + 0xFF, // size + 0x57, 0x41, 0x56, + 0x45, // WAVE + 0x66, 0x6d, 0x74, + 0x20, // fmt + 0x10, 0x00, 0x00, + 0x00, // subchunk1size + 0x01, 0x00, // audio format - pcm + 0x02, 0x00, // numof channels + 0x44, 0xac, 0x00, + 0x00, //, //samplerate 44k1: 0x44, 0xac, 0x00, 0x00 48k: 48000: 0x80, 0xbb, 0x00, 0x00, + 0x10, 0xb1, 0x02, + 0x00, // byterate + 0x04, 0x00, // blockalign + 0x10, 0x00, // bits per sample - 16 + 0x64, 0x61, 0x74, + 0x61, // subchunk3id -"data" + 0xFF, 0xFF, 0xFF, + 0xFF // subchunk3size (endless) +}; +const char* afName[] = { + "unknown", "RIFF", "Ogg", "MP1", "MP2", "MP3", "AAC MP4", + "AAC ADTS", "AAC ADIF", "FLAC", "WMA", "MIDI", "DSD64", "LATM/LOAS", +}; +VS1053_SINK::VS1053_SINK() { + // PIN CONFIG + // DREQ + BELL_LOG(info, TAG, "VS1053_DREQ=%d", CONFIG_GPIO_VS_DREQ); + isRunning = true; + gpio_config_t gpio_conf; + gpio_conf.mode = GPIO_MODE_INPUT; + gpio_conf.pull_up_en = GPIO_PULLUP_DISABLE; + gpio_conf.pull_down_en = GPIO_PULLDOWN_ENABLE; + gpio_conf.intr_type = GPIO_INTR_DISABLE; + gpio_conf.pin_bit_mask = ((uint64_t)(((uint64_t)1) << CONFIG_GPIO_VS_DREQ)); + ESP_ERROR_CHECK(gpio_config(&gpio_conf)); + // CS + BELL_LOG(info, TAG, "VS1053_CS=%d", CONFIG_GPIO_VS_CS); + gpio_reset_pin((gpio_num_t)CONFIG_GPIO_VS_CS); + gpio_set_direction((gpio_num_t)CONFIG_GPIO_VS_CS, GPIO_MODE_OUTPUT); + gpio_set_level((gpio_num_t)CONFIG_GPIO_VS_CS, 1); + // DCS + BELL_LOG(info, TAG, "VS1053_DCS=%d", CONFIG_GPIO_VS_DCS); + gpio_reset_pin((gpio_num_t)CONFIG_GPIO_VS_DCS); + gpio_set_direction((gpio_num_t)CONFIG_GPIO_VS_DCS, GPIO_MODE_OUTPUT); + gpio_set_level((gpio_num_t)CONFIG_GPIO_VS_DCS, 1); + // RESET + BELL_LOG(info, TAG, "VS1053_RESET=%d", CONFIG_GPIO_VS_RESET); + if (CONFIG_GPIO_VS_RESET >= 0) { + gpio_reset_pin((gpio_num_t)CONFIG_GPIO_VS_RESET); + gpio_set_direction((gpio_num_t)CONFIG_GPIO_VS_RESET, GPIO_MODE_OUTPUT); + gpio_set_level((gpio_num_t)CONFIG_GPIO_VS_RESET, 0); + vTaskDelay(100 / portTICK_PERIOD_MS); + gpio_set_level((gpio_num_t)CONFIG_GPIO_VS_RESET, 1); + } +} + +esp_err_t VS1053_SINK::init(spi_host_device_t SPI, + SemaphoreHandle_t* SPI_semaphore) { + esp_err_t ret; + this->SPI_semaphore = SPI_semaphore; + // SPI CONFIG + uint32_t freq = spi_get_actual_clock(APB_CLK_FREQ, 1400000, 128); + spi_device_interface_config_t devcfg; + memset(&devcfg, 0, sizeof(spi_device_interface_config_t)); + BELL_LOG(info, TAG, "VS1053 LOWFreq: %lu", freq); + + devcfg.clock_speed_hz = freq, devcfg.command_bits = 8, + devcfg.address_bits = 8, devcfg.dummy_bits = 0, devcfg.duty_cycle_pos = 0, + devcfg.cs_ena_pretrans = 0, devcfg.cs_ena_posttrans = 1, devcfg.flags = 0, + devcfg.mode = 0, devcfg.spics_io_num = CONFIG_GPIO_VS_CS, + devcfg.queue_size = 1, + devcfg.pre_cb = NULL, // Specify pre-transfer callback to handle D/C line + devcfg.post_cb = NULL; + + BELL_LOG(info, TAG, "spi device interface config done, VERSION : %i", + VERSION); + ret = spi_bus_add_device(SPI, &devcfg, &this->SPIHandleLow); + BELL_LOG(info, TAG, "spi_bus_add_device=%d", ret); + assert(ret == ESP_OK); + // SPI TEST SLOW-/HIGH-SPEED + vTaskDelay(20 / portTICK_PERIOD_MS); + write_register(SCI_MODE, SM_SDINEW | SM_TESTS | SM_RESET); + ret = test_comm("Slow SPI,Testing VS1053 read/write registers...\n"); + if (ret != ESP_OK) + return ret; + { + freq = spi_get_actual_clock(APB_CLK_FREQ, 6670000, 128); + write_register( + SCI_CLOCKF, + HZ_TO_SC_FREQ(12288000) | SC_MULT_53_45X | + SC_ADD_53_00X); // Normal clock settings multiplyer 3.0 = 12.2 MHz + BELL_LOG(info, TAG, "VS1053 HighFreq: %lu", freq); + devcfg.clock_speed_hz = freq, devcfg.command_bits = 0, + devcfg.address_bits = 0, devcfg.spics_io_num = CONFIG_GPIO_VS_DCS; + ret = spi_bus_add_device(SPI, &devcfg, &this->SPIHandleFast); + BELL_LOG(info, TAG, "spi_bus_add_device=%d", ret); + assert(ret == ESP_OK); + ret = test_comm("Slow SPI,Testing VS1053 read/write registers...\n"); + if (ret != ESP_OK) + return ret; + } + vTaskDelay(100 / portTICK_PERIOD_MS); + + write_mem(PAR_CONFIG1, PAR_CONFIG1_AAC_SBR_SELECTIVE_UPSAMPLE); + write_register(SCI_VOL, 0x0c0c); +#ifndef CONFIG_VS1053_NO_PLUGIN + load_user_code(PLUGIN, PLUGIN_SIZE); +#endif + vTaskDelay(100 / portTICK_PERIOD_MS); + xTaskCreate(vs_feed, "track_feed", 4098 * 4, (void*)this, 4, &task_handle); + //xTaskCreatePinnedToCore(vs_feed, "track_feed", 1028 * 20, (void*)this, 1, &task_handle, 1); + return ESP_OK; +} + +VS1053_SINK::~VS1053_SINK() { + if (task_handle != NULL) + vTaskDelete(task_handle); + command_callbacks.clear(); + task_handle = NULL; + isRunning = false; +} +// LOOP +VS1053_TRACK::VS1053_TRACK(size_t track_id, size_t buffer_size) { + this->track_id = track_id; + ucBufferStorage = (uint8_t*)malloc(buffer_size); + this->dataBuffer = xStreamBufferCreateStatic(buffer_size, 1, ucBufferStorage, + &xStaticStreamBuffer); + // this->run_track(); + + if (dataBuffer == NULL) { + BELL_LOG(error, TAG, "not enough heap memory\n"); + /* There was not enough heap memory space available to create the + stream buffer. */ + } +} +VS1053_TRACK::~VS1053_TRACK() { + vStreamBufferDelete(dataBuffer); + free(ucBufferStorage); +} + +void VS1053_SINK::new_track(std::shared_ptr track) { + tracks.push_back(track); +} +bool VS1053_SINK::is_seekable(VS1053_TRACK::VS_TRACK_STATE* state) { + if (read_register(SCI_STATUS) >> SS_DO_NOT_JUMP_B == 0) { + new_state(*state, VS1053_TRACK::VS_TRACK_STATE::tsPlaybackSeekable); + return true; + } + return false; +} +size_t VS1053_SINK::track_seekable(size_t track_id) { + if (tracks.size()) + if (tracks[0]->track_id == track_id) + return tracks[0]->header_size; + return 0; +} +void VS1053_SINK::cancel_track(VS1053_TRACK::VS_TRACK_STATE* state) { + unsigned short oldMode; + oldMode = read_register(SCI_MODE); + write_register(SCI_MODE, oldMode | SM_CANCEL); + new_state(*state, VS1053_TRACK::VS_TRACK_STATE::tsCancelAwait); +} +bool VS1053_SINK::is_cancelled(VS1053_TRACK::VS_TRACK_STATE* state, + uint8_t endFillByte, size_t endFillBytes) { + if (read_register(SCI_MODE) & SM_CANCEL) + sdi_send_fillers(endFillByte, 2); + else { + sdi_send_fillers(endFillByte, endFillBytes); + new_state(*state, VS1053_TRACK::VS_TRACK_STATE::tsStopped); + return true; + } + return false; +} +void VS1053_SINK::delete_all_tracks(void) { + if (this->tracks.size() > 1) + this->tracks.erase(tracks.begin() + 1, tracks.end()); + if (!this->tracks.size()) + return; + if (this->tracks[0]->state != VS1053_TRACK::VS_TRACK_STATE::tsStopped) + new_state(this->tracks[0]->state, VS1053_TRACK::VS_TRACK_STATE::tsCancel); +} +size_t VS1053_SINK::get_track_info(size_t pos, uint8_t& endFillByte, + size_t& endFillBytes) { +#ifdef CONFIG_REPORT_ON_SCREEN + uint16_t sampleRate; + uint32_t byteRate; +#endif + get_audio_format(&audioFormat, &endFillBytes); + + /* It is important to collect endFillByte while still in normal + playback. If we need to later cancel playback or run into any + trouble with e.g. a broken file, we need to be able to repeatedly + send this byte until the decoder has been able to exit. */ + + endFillByte = read_mem(PAR_END_FILL_BYTE); +#ifdef CONFIG_REPORT_ON_SCREEN + + sampleRate = read_register(SCI_AUDATA); + byteRate = read_mem(PAR_BYTERATE); + /* FLAC: byteRate = bitRate / 32 + Others: byteRate = bitRate / 8 + Here we compensate for that difference. */ + if (audioFormat == afFlac) + byteRate *= 4; + + BELL_LOG(info, TAG, + "Track %i, " + "%dKiB " + "%1ds %1.1f" + "kb/s %dHz %s %s", + tracks[0]->track_id, pos / (1024 / VS1053_PACKET_SIZE), + read_register(SCI_DECODE_TIME), byteRate * (8.0 / 1000.0), + sampleRate & 0xFFFE, (sampleRate & 1) ? "stereo" : "mono", + afName[audioFormat]); +#endif + return (audioFormat == afMidi || audioFormat == afUnknown) + ? REPORT_INTERVAL_MIDI + : REPORT_INTERVAL; +} + +size_t VS1053_TRACK::feed_data(uint8_t* data, size_t len, + bool STORAGE_VOLATILE) { + if (STORAGE_VOLATILE) + if (this->header_size) + xStreamBufferReset(this->dataBuffer); + size_t res = + xStreamBufferSend(this->dataBuffer, (void*)data, len, pdMS_TO_TICKS(30)); + return res; +} +size_t VS1053_SINK::spaces_available(size_t track_id) { + if (this->tracks.size()) + for (auto track : tracks) + if (track->track_id == track_id) + return xStreamBufferSpacesAvailable(track->dataBuffer); + return 0; +} +void VS1053_TRACK::empty_feed() { + if (this->dataBuffer != NULL) + xStreamBufferReset(this->dataBuffer); +} +void VS1053_SINK::new_state(VS1053_TRACK::VS_TRACK_STATE& state, + VS1053_TRACK::VS_TRACK_STATE new_state) { + state = new_state; + BELL_LOG(info, TAG, "New state %i", new_state); + if (state_callback != NULL) { + state_callback((uint8_t)new_state); + } +} + +void VS1053_SINK::run_feed(size_t FILL_BUFFER_BEFORE_PLAYBACK) { + uint8_t* item = (uint8_t*)malloc(VS1053_PACKET_SIZE); + while (isRunning) { + if (tracks.size()) { + size_t itemSize = 0; + uint32_t pos = 0; + long nextReportPos = 0; // File pointer where to next collect/report + std::shared_ptr track = tracks.front(); + uint8_t endFillByte = 0; // Byte to send when stopping song + size_t endFillBytes = SDI_END_FILL_BYTES; + playMode = read_mem(PAR_PLAY_MODE); + sdi_send_fillers(endFillByte, endFillBytes); + write_register(SCI_DECODE_TIME, 0); // Reset DECODE_TIME + new_state(track->state, VS1053_TRACK::VS_TRACK_STATE::tsPlaybackStart); + while (track->state != VS1053_TRACK::VS_TRACK_STATE::tsStopped) { + if (this->command_callbacks.size()) { + this->command_callbacks[0](track->track_id); + this->command_callbacks.pop_front(); + } + + switch (track->state) { + case VS1053_TRACK::VS_TRACK_STATE::tsPlaybackStart: + this->new_state( + track->state, + VS1053_TRACK::VS1053_TRACK::VS_TRACK_STATE::tsPlayback); + goto tsPlaybackSeekable; + case VS1053_TRACK::VS_TRACK_STATE::tsPlayback: + if (this->is_seekable(&track->state)) + if (!track->header_size) + track->header_size = VS1053_PACKET_SIZE * pos; + goto tsPlaybackSeekable; + case VS1053_TRACK::VS_TRACK_STATE::tsPlaybackSeekable: + + tsPlaybackSeekable: + itemSize = + xStreamBufferReceive(track->dataBuffer, (void*)item, + VS1053_PACKET_SIZE, pdMS_TO_TICKS(30)); + if (itemSize) { + this->sdi_send_buffer(item, itemSize); + pos++; + } + break; + case VS1053_TRACK::VS_TRACK_STATE::tsSoftCancel: + if (xStreamBufferBytesAvailable(track->dataBuffer)) + goto tsPlaybackSeekable; + this->new_state(track->state, + VS1053_TRACK::VS_TRACK_STATE::tsCancel); + [[fallthrough]]; + case VS1053_TRACK::VS_TRACK_STATE::tsCancel: + track->empty_feed(); + this->cancel_track(&track->state); + [[fallthrough]]; + case VS1053_TRACK::VS_TRACK_STATE::tsCancelAwait: + if (this->is_cancelled(&track->state, endFillByte, endFillBytes)) {} + break; + default: + vTaskDelay(20 / portTICK_PERIOD_MS); + break; + } + if (pos >= nextReportPos) { + nextReportPos += this->get_track_info(pos, endFillByte, endFillBytes); + } + } + tracks.pop_front(); + } + vTaskDelay(50 / portTICK_PERIOD_MS); + } + task_handle = NULL; + vTaskDelete(NULL); +} +// FEED FUNCTIONS + +size_t VS1053_SINK::data_request(std::shared_ptr track) { + return xStreamBufferSpacesAvailable(track->dataBuffer); +} + +void VS1053_SINK::stop_feed() { + if (this->tracks[0]->state <= 4) + new_state(this->tracks[0]->state, VS1053_TRACK::VS_TRACK_STATE::tsCancel); +} +void VS1053_SINK::soft_stop_feed() { + if (this->tracks[0]->state <= 3) + new_state(this->tracks[0]->state, + VS1053_TRACK::VS_TRACK_STATE::tsSoftCancel); +} + +// COMMAND FUCNTIONS +/* The command pipeline recieves command in a structure of uint8_t[]. + */ +uint8_t VS1053_SINK::feed_command(command_callback commandCallback) { + if (this->tracks.size()) { + command_callbacks.push_back(commandCallback); + } else + commandCallback(0); + return 0; +} +void VS1053_SINK::set_volume_logarithmic(size_t vol) { + float value = log10((float)vol / 0xFFFF * 100 + 1); + if (value >= 2.0) + value = 2.0; + size_t logVolume = value / 2 * 100; // *100 + + this->set_volume(logVolume); +} +/** + * set_volume accepts values from 0 to 100 + */ +void VS1053_SINK::set_volume(uint8_t vol) { + vol = vol > 100 ? 0 : 100 - vol; + uint16_t value = (vol << 8) | vol; + write_register(SCI_VOL, value); // Volume left and right +} + +void VS1053_SINK::set_volume(uint8_t left, uint8_t right) { + left = left > 100 ? 0 : 100 - left; + right = right > 100 ? 0 : 100 - right; + uint16_t value = (left << 8) | right; + write_register(SCI_VOL, value); // Volume left and right +} + +void VS1053_SINK::get_audio_format(Audio_Format* audioFormat, + size_t* endFillBytes) { + uint16_t h1 = read_register(SCI_HDAT1); + *audioFormat = afUnknown; + switch (h1) { + case 0x7665: + *audioFormat = afRiff; + goto sdi_end_fill_bytes; + case 0x4444: + *audioFormat = afDsd64; + goto sdi_end_fill_bytes_flac; + case 0x4c41: + *audioFormat = afLatm; + // set OUT_OF_WAV bit of SCI_MODE; + goto sdi_end_fill_bytes_flac; + case 0x4154: + *audioFormat = afAacAdts; + goto sdi_end_fill_bytes; + case 0x4144: + *audioFormat = afAacAdif; + goto sdi_end_fill_bytes; + case 0x574d: + *audioFormat = afWma; + goto sdi_end_fill_bytes; + case 0x4f67: + *audioFormat = afOggVorbis; + goto sdi_end_fill_bytes; + case 0x664c: + *audioFormat = afFlac; + goto sdi_end_fill_bytes_flac; + case 0x4d34: + *audioFormat = afAacMp4; + goto sdi_end_fill_bytes; + case 0x4d54: + *audioFormat = afMidi; + goto sdi_end_fill_bytes; + default: + h1 &= 0xffe6; + if (h1 == 0xffe2) + *audioFormat = afMp2; + else if (h1 == 0xffe4) + *audioFormat = afMp2; + else if (h1 == 0xffe6) + *audioFormat = afMp1; + if (*audioFormat == afUnknown) + goto sdi_end_fill_bytes_flac; + sdi_end_fill_bytes: + *endFillBytes = SDI_END_FILL_BYTES; + break; + sdi_end_fill_bytes_flac: + *endFillBytes = SDI_END_FILL_BYTES_FLAC; + break; + } +} + +// SPI COMMUNICATION TEST +const uint16_t chipNumber[16] = {1001, 1011, 1011, 1003, 1053, 1033, 1063, 1103, + 0, 0, 0, 0, 0, 0, 0, 0}; + +esp_err_t VS1053_SINK::test_comm(const char* header) { + // Test the communication with the VS1053 module. The result wille be returned. + // If DREQ is low, there is problably no VS1053 connected. Pull the line HIGH + // in order to prevent an endless loop waiting for this signal. The rest of the + // software will still work, but readbacks from VS1053 will fail. + + write_register(SCI_AICTRL1, 0xABAD); + write_register(SCI_AICTRL2, 0x7E57); + if (read_register(SCI_AICTRL1) != 0xABAD || + read_register(SCI_AICTRL2) != 0x7E57) { + BELL_LOG(info, TAG, "There is something wrong with VS10xx SCI registers\n"); + return ESP_ERR_INVALID_RESPONSE; + } + write_register(SCI_AICTRL1, 0); + write_register(SCI_AICTRL2, 0); + uint16_t ssVer = ((read_register(SCI_STATUS) >> 4) & 15); + if (chipNumber[ssVer]) { + BELL_LOG(info, TAG, "Chip is VS%d\n", chipNumber[ssVer]); + if (chipNumber[ssVer] != 1053) { + BELL_LOG(info, TAG, "Incorrect chip\n"); + return ESP_ERR_NOT_SUPPORTED; + } + } else { + BELL_LOG(info, TAG, "Unknown VS10xx SCI_MODE field SS_VER = %d\n", ssVer); + return ESP_ERR_NOT_FOUND; + } + + return ESP_OK; +} + +// PLUGIN FUNCTION + +void VS1053_SINK::load_user_code(const unsigned short* plugin, + uint16_t sizeofpatch) { + BELL_LOG(info, TAG, "Loading patch"); + await_data_request(); + int i = 0; + while (i < sizeofpatch) { + unsigned short addr, n, val; + addr = plugin[i++]; + n = plugin[i++]; + if (n & 0x8000U) { /* RLE run, replicate n samples */ + n &= 0x7FFF; + val = plugin[i++]; + while (n--) { + write_register(addr, val); + } + } else { /* Copy run, copy n samples */ + while (n--) { + val = plugin[i++]; + write_register(addr, val); + } + } + } +} + +// GPIO FUNCTIONS + +void VS1053_SINK::await_data_request() { + while (!gpio_get_level((gpio_num_t)CONFIG_GPIO_VS_DREQ)) + vTaskDelay(10 / portTICK_PERIOD_MS); +} +// WRITE/READ FUNCTIONS + +uint16_t VS1053_SINK::read_register(uint8_t _reg) { + spi_transaction_t SPITransaction; + esp_err_t ret; + await_data_request(); // Wait for DREQ to be HIGH + memset(&SPITransaction, 0, sizeof(spi_transaction_t)); + SPITransaction.length = 16; + SPITransaction.flags |= SPI_TRANS_USE_RXDATA; + SPITransaction.cmd = VS_READ_COMMAND; + SPITransaction.addr = _reg; + if (SPI_semaphore != NULL) + if (xSemaphoreTake(*SPI_semaphore, portMAX_DELAY) != pdTRUE) + return 0; + ret = spi_device_transmit(this->SPIHandleLow, &SPITransaction); + assert(ret == ESP_OK); + uint16_t result = (((SPITransaction.rx_data[0] & 0xFF) << 8) | + ((SPITransaction.rx_data[1]) & 0xFF)); + await_data_request(); // Wait for DREQ to be HIGH again + if (SPI_semaphore != NULL) + xSemaphoreGive(*SPI_semaphore); + return result; +} + +bool VS1053_SINK::write_register(uint8_t _reg, uint16_t _value) { + spi_transaction_t SPITransaction; + esp_err_t ret; + + await_data_request(); // Wait for DREQ to be HIGH + memset(&SPITransaction, 0, sizeof(spi_transaction_t)); + SPITransaction.flags |= SPI_TRANS_USE_TXDATA; + SPITransaction.cmd = VS_WRITE_COMMAND; + SPITransaction.addr = _reg; + SPITransaction.tx_data[0] = (_value >> 8) & 0xFF; + SPITransaction.tx_data[1] = (_value & 0xFF); + SPITransaction.length = 16; + if (SPI_semaphore != NULL) + if (xSemaphoreTake(*SPI_semaphore, portMAX_DELAY) != pdTRUE) + return false; + ret = spi_device_transmit(this->SPIHandleLow, &SPITransaction); + assert(ret == ESP_OK); + await_data_request(); // Wait for DREQ to be HIGH again + if (SPI_semaphore != NULL) + xSemaphoreGive(*SPI_semaphore); + return true; +} + +uint32_t VS1053_SINK::read_mem32(uint16_t addr) { + uint16_t result; + + write_register(SCI_WRAMADDR, addr); + // Note: transfer16 does not seem to work + result = read_register(SCI_WRAM); + return result | ((uint32_t)read_register(SCI_WRAM) << 16); +} + +uint32_t VS1053_SINK::read_mem32_counter(uint16_t addr) { + uint16_t msbV1, lsb, msbV2; + uint32_t res; + write_register(SCI_WRAMADDR, addr); + msbV1 = read_register(SCI_WRAM); + write_register(SCI_WRAMADDR, addr); + lsb = read_register(SCI_WRAM); + msbV2 = read_register(SCI_WRAM); + if (lsb < 0x8000U) { + msbV1 = msbV2; + } + res = ((uint32_t)msbV1 << 16) | lsb; + + return res; +} + +uint16_t VS1053_SINK::read_mem(uint16_t addr) { + write_register(SCI_WRAMADDR, addr); + return read_register(SCI_WRAM); +} + +/* + Write 16-bit value to given VS10xx address +*/ +void VS1053_SINK::write_mem(uint16_t addr, uint16_t data) { + write_register(SCI_WRAMADDR, addr); + write_register(SCI_WRAM, data); +} + +/* + Write 32-bit value to given VS10xx address +*/ +void VS1053_SINK::write_mem32(uint16_t addr, uint32_t data) { + write_register(SCI_WRAMADDR, addr); + write_register(SCI_WRAM, (uint16_t)data); + write_register(SCI_WRAM, (uint16_t)(data >> 16)); +} +bool VS1053_SINK::sdi_send_buffer(uint8_t* data, size_t len) { + size_t chunk_length; // Length of chunk 32 byte or shorter + spi_transaction_t SPITransaction; + esp_err_t ret; + if (SPI_semaphore != NULL) + if (xSemaphoreTake(*SPI_semaphore, portMAX_DELAY) != pdTRUE) + return false; + while (len) // More to do? + { + await_data_request(); // Wait for space available + chunk_length = len; + if (len > VS1053_CHUNK_SIZE) { + chunk_length = VS1053_CHUNK_SIZE; + } + len -= chunk_length; + memset(&SPITransaction, 0, sizeof(spi_transaction_t)); + SPITransaction.length = chunk_length * 8; + SPITransaction.tx_buffer = data; + // while(spi_device_acquire_bus(this->SPIHandleFast,portMAX_DELAY)!=ESP_OK){}; + ret = spi_device_transmit(this->SPIHandleFast, &SPITransaction); + // spi_device_release_bus(this->SPIHandleFast); + assert(ret == ESP_OK); + data += chunk_length; + } + if (SPI_semaphore != NULL) + xSemaphoreGive(*SPI_semaphore); + + return true; +} + +bool VS1053_SINK::sdi_send_fillers(uint8_t endFillByte, size_t len) { + size_t chunk_length; // Length of chunk 32 byte or shorter + spi_transaction_t SPITransaction; + esp_err_t ret; + uint8_t data[VS1053_CHUNK_SIZE]; + for (int i = 0; i < VS1053_CHUNK_SIZE; i++) + data[i] = endFillByte; + if (SPI_semaphore != NULL) + if (xSemaphoreTake(*SPI_semaphore, portMAX_DELAY) != pdTRUE) + return false; + while (len) // More to do? + { + await_data_request(); // Wait for space available + chunk_length = len; + if (len > VS1053_CHUNK_SIZE) { + chunk_length = VS1053_CHUNK_SIZE; + } + len -= chunk_length; + + memset(&SPITransaction, 0, sizeof(spi_transaction_t)); + SPITransaction.length = chunk_length * 8; + SPITransaction.tx_buffer = data; + spi_device_acquire_bus(this->SPIHandleFast, portMAX_DELAY); + ret = spi_device_transmit(this->SPIHandleFast, &SPITransaction); + spi_device_release_bus(this->SPIHandleFast); + assert(ret == ESP_OK); + } + if (SPI_semaphore != NULL) + xSemaphoreGive(*SPI_semaphore); + return true; +} + +void VS1053_SINK::wram_write(uint16_t address, uint16_t data) { + write_register(SCI_WRAMADDR, address); + write_register(SCI_WRAM, data); +} + +uint16_t VS1053_SINK::wram_read(uint16_t address) { + write_register(SCI_WRAMADDR, address); // Start reading from WRAM + return read_register(SCI_WRAM); // Read back result +} diff --git a/targets/esp32/main/CMakeLists.txt b/targets/esp32/main/CMakeLists.txt index 2f93f16c..2a3fa725 100644 --- a/targets/esp32/main/CMakeLists.txt +++ b/targets/esp32/main/CMakeLists.txt @@ -18,5 +18,5 @@ option(BUILD_TESTING OFF) add_subdirectory("../../../cspot" ${CMAKE_CURRENT_BINARY_DIR}/cspot) # Configure the target -target_link_libraries(${COMPONENT_LIB} PUBLIC cspot) + target_link_libraries(${COMPONENT_LIB} PUBLIC cspot) target_compile_options(${COMPONENT_LIB} PRIVATE -std=gnu++17) diff --git a/targets/esp32/main/ESPStatusLed.cpp b/targets/esp32/main/ESPStatusLed.cpp index 9cd25bb5..0ed17e6c 100644 --- a/targets/esp32/main/ESPStatusLed.cpp +++ b/targets/esp32/main/ESPStatusLed.cpp @@ -1,4 +1,4 @@ -#include "ESPStatusLed.h" +/*#include "ESPStatusLed.h" static const char* TAG = "statusled"; @@ -80,4 +80,5 @@ void ESPStatusLed::setStatus(StatusLed newStatus) { ESP_LOGI(TAG, "Chaing status to %d", this->status); this->status = newStatus; -} \ No newline at end of file +} +*/ \ No newline at end of file diff --git a/targets/esp32/main/ESPStatusLed.h b/targets/esp32/main/ESPStatusLed.h index 14cc0905..53ef8d55 100644 --- a/targets/esp32/main/ESPStatusLed.h +++ b/targets/esp32/main/ESPStatusLed.h @@ -1,11 +1,11 @@ -#ifndef ESPSTATUSLED_H +/*#ifndef ESPSTATUSLED_H #define ESPSTATUSLED_H #include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" #include "driver/gpio.h" #include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" #include "led_strip.h" #include "sdkconfig.h" @@ -34,3 +34,4 @@ class ESPStatusLed }; #endif +*/ \ No newline at end of file diff --git a/targets/esp32/main/EspPlayer.cpp b/targets/esp32/main/EspPlayer.cpp new file mode 100644 index 00000000..66147c1b --- /dev/null +++ b/targets/esp32/main/EspPlayer.cpp @@ -0,0 +1,157 @@ +#include "EspPlayer.h" + +#include // for uint8_t +#include // for __base +#include // for operator<<, basic_ostream, endl, cout +#include // for shared_ptr, make_shared, make_unique +#include // for scoped_lock +#include // for hash, string_view +#include // for remove_extent_t +#include // for move +#include // for get +#include // for vector + +#include "BellUtils.h" // for BELL_SLEEP_MS +#include "CircularBuffer.h" +#include "DeviceStateHandler.h" // for SpircHandler, DeviceStateHandler::CommandType +#include "Logger.h" +#include "StreamInfo.h" // for BitWidth, BitWidth::BW_16 +#include "TrackPlayer.h" // for TrackPlayer + +EspPlayer::EspPlayer(std::shared_ptr sink, + std::shared_ptr handler) + : bell::Task("player", 12 * 1024, 0, 1) { + this->handler = handler; + this->audioSink = std::move(sink); + + this->circularBuffer = std::make_shared(1024 * 128); + + this->handler->trackPlayer->setDataCallback( + [this](uint8_t* data, size_t bytes, size_t trackId, + bool STORAGE_VOLATILE) { + this->feedData(data, bytes, trackId); + return bytes; + }); + + this->isPaused = false; + + this->handler->stateCallback = + [this](cspot::DeviceStateHandler::Command event) { + switch (event.commandType) { + case cspot::DeviceStateHandler::CommandType::PAUSE: + this->pauseRequested = true; + break; + case cspot::DeviceStateHandler::CommandType::PLAY: + this->isPaused = false; + this->pauseRequested = false; + break; + case cspot::DeviceStateHandler::CommandType::DISC: + this->circularBuffer->emptyBuffer(); + tracks.at(0)->trackMetrics->endTrack(); + this->handler->ctx->playbackMetrics->sendEvent(tracks[0]); + tracks.clear(); + this->playlistEnd = true; + break; + case cspot::DeviceStateHandler::CommandType::FLUSH: + this->circularBuffer->emptyBuffer(); + break; + case cspot::DeviceStateHandler::CommandType::SEEK: + this->circularBuffer->emptyBuffer(); + break; + case cspot::DeviceStateHandler::CommandType::SKIP_NEXT: + case cspot::DeviceStateHandler::CommandType::SKIP_PREV: + this->circularBuffer->emptyBuffer(); + break; + case cspot::DeviceStateHandler::CommandType::PLAYBACK_START: + this->circularBuffer->emptyBuffer(); + this->isPaused = false; + this->playlistEnd = false; + if (tracks.size()) + tracks.clear(); + break; + case cspot::DeviceStateHandler::CommandType::PLAYBACK: + tracks.push_back( + std::get>(event.data)); + this->isPaused = false; + this->playlistEnd = false; + break; + case cspot::DeviceStateHandler::CommandType::DEPLETED: + this->circularBuffer->emptyBuffer(); + this->playlistEnd = true; + break; + case cspot::DeviceStateHandler::CommandType::VOLUME: { + int volume = std::get(event.data); + break; + } + default: + break; + } + }; + startTask(); +} + +void EspPlayer::feedData(uint8_t* data, size_t len, size_t trackId) { + size_t toWrite = len; + + while (toWrite > 0) { + this->current_hash = trackId; + size_t written = + this->circularBuffer->write(data + (len - toWrite), toWrite); + if (written == 0) { + BELL_SLEEP_MS(10); + } + + toWrite -= written; + } +} + +void EspPlayer::runTask() { + std::vector outBuf = std::vector(1024); + + std::scoped_lock lock(runningMutex); + + size_t lastHash = 0; + + while (isRunning) { + if (!this->isPaused) { + size_t read = this->circularBuffer->read(outBuf.data(), outBuf.size()); + if (this->pauseRequested) { + this->pauseRequested = false; + this->isPaused = true; + } + + this->audioSink->feedPCMFrames(outBuf.data(), read); + + if (read == 0) { + BELL_SLEEP_MS(10); + continue; + } else { + if (lastHash != current_hash) { + if (lastHash) { + tracks.at(0)->trackMetrics->endTrack(); + this->handler->ctx->playbackMetrics->sendEvent(tracks[0]); + CSPOT_LOG(info, "TRACK ENDED, new track %i", current_hash); + if (tracks.size()) { + tracks.pop_front(); + if (this->playlistEnd) { + tracks.clear(); + } + } + this->handler->trackPlayer->onTrackEnd(true); + } + lastHash = current_hash; + tracks.at(0)->trackMetrics->startTrackPlaying( + tracks.at(0)->requestedPosition); + this->handler->putPlayerState(); + } + } + } else { + BELL_SLEEP_MS(100); + } + } +} + +void EspPlayer::disconnect() { + isRunning = false; + std::scoped_lock lock(runningMutex); +} diff --git a/targets/esp32/main/EspPlayer.h b/targets/esp32/main/EspPlayer.h new file mode 100644 index 00000000..713f2786 --- /dev/null +++ b/targets/esp32/main/EspPlayer.h @@ -0,0 +1,43 @@ +#pragma once + +#include // for size_t +#include // for uint8_t +#include // for atomic +#include // for shared_ptr, unique_ptr +#include // for mutex +#include // for string + +#include "AudioSink.h" // for AudioSink +#include "BellTask.h" // for Task +#include "DeviceStateHandler.h" // for DeviceStateHandler + +namespace bell { +class CircularBuffer; +} // namespace bell +namespace cspot { +class DeviceStateHandler; +} // namespace cspot + +class EspPlayer : public bell::Task { + public: + EspPlayer(std::shared_ptr sink, + std::shared_ptr handler); + void disconnect(); + + private: + std::string currentTrackId; + std::shared_ptr handler; + std::shared_ptr audioSink; + std::shared_ptr circularBuffer; + std::deque> tracks = {}; + void feedData(uint8_t* data, size_t len, size_t); + + std::atomic pauseRequested = false; + std::atomic isPaused = true; + std::atomic isRunning = true; + std::mutex runningMutex; + std::atomic playlistEnd = false; + size_t current_hash; + + void runTask() override; +}; diff --git a/targets/esp32/main/Kconfig.projbuild b/targets/esp32/main/Kconfig.projbuild index b0a46638..977a9ba9 100644 --- a/targets/esp32/main/Kconfig.projbuild +++ b/targets/esp32/main/Kconfig.projbuild @@ -8,10 +8,12 @@ menu "CSPOT Configuration" choice CSPOT_SINK prompt "Sink Device" - default CSPOT_SINK_AC101 + default CSPOT_SINK_INTERNAL help Select audio sink device + config BELL_NOCODEC + bool "VS1053" config CSPOT_SINK_INTERNAL bool "Built-in DAC" config CSPOT_SINK_AC101 @@ -28,17 +30,30 @@ menu "CSPOT Configuration" choice CSPOT_QUALITY prompt "Audio Quality (BPS)" - default CSPOT_QUALITY_320 + default VORBIS_160 help Audio quality (not used currently) - config CSPOT_QUALITY_320 + config VORBIS_320 bool "320 bps" - config CSPOT_QUALITY_160 + config VORBIS_160 bool "160 bps" - config CSPOT_QUALITY_96 + config VORBIS_96 bool "96 bps" endchoice + config CSPOT_AUDIO_FORMAT + int + default 0 if VORBIS_96 + default 1 if VORBIS_160 + default 2 if VORBIS_320 + default 3 if MP3_256 + default 4 if MP3_320 + default 5 if MP3_160 + default 6 if MP3_96 + default 7 if MP3_160_ENC + default 8 if AAC_24 + default 9 if AAC_48 + choice CSPOT_STATUS_LED_TYPE prompt "Status LED type" default CSPOT_STATUS_LED_TYPE_NONE @@ -53,6 +68,72 @@ menu "CSPOT Configuration" bool "RMT - Addressable LED" endchoice + choice CSPOT_LOGIN + prompt "Login type" + default CSPOT_LOGIN_ZEROCONF + help + Select login form + + config CSPOT_LOGIN_ZEROCONF + bool "Login with zeroconfServer" + help + login with zeroconf + config CSPOT_LOGIN_PASS + bool "Login with password" + endchoice + + menu "Username & password" + visible if CSPOT_LOGIN_PASS + config CSPOT_LOGIN_USERNAME + string "Spotify username" + default "username" + config CSPOT_LOGIN_PASSWORD + string "Spotify password" + default "password" + help + login with username and password + endmenu + + choice CSPOT_DISCOVERY_MODE + prompt "CSpot Device Visibility Mode" + default CSPOT_DISCOVERY_MODE_OPEN + + config CSPOT_DISCOVERY_MODE_OPEN + bool "Always visible in local network" + help + In this mode, the mDNS announcement remains active, making the device + visible to all devices on the local network, even while it is actively + connected and controlled. Playback rights can be transferred to another + device without disconnecting. + + config CSPOT_DISCOVERY_MODE_VISIBLE_ON_DISCONNECTED + bool "Visible only when disconnected" + help + In this mode, the mDNS announcement is disabled when the device is + actively connected and controlled. The device becomes visible on the + local network only after it is disconnected or playback rights are + transferred. + endchoice + + config CSPOT_STAY_CONNECTED_ON_TRANSFER + bool "Stay connected on playback transfer" + help + Enable this option to keep the CSpot device logged in and accessible during + a playback rights transfer. If enabled, the device will remain accessible + to other Spotify devices logged in with the same account after playback transfer. + + Note: If the device visibility is set to "Visible only when disconnected," + the mDNS announcement will remain disabled during playback and playback transfers. + The device will only announce itself on the local network after it is + disconnected or an explicit mDNS "/close" command is received. + + config UPDATE_FUTURE_TRACKS + int "Send tracks to spotify" + range 0 100 + default 10 + help + How many tracks are visible in the currently playing header + config CSPOT_STATUS_LED_GPIO int "Status LED GPIO number" range 0 48 diff --git a/targets/esp32/main/VSPlayer.cpp b/targets/esp32/main/VSPlayer.cpp new file mode 100644 index 00000000..dc4c29c9 --- /dev/null +++ b/targets/esp32/main/VSPlayer.cpp @@ -0,0 +1,138 @@ +#include "VSPlayer.h" + +#include // for BELL_LOG +#include // for uint8_t +#include // for operator<<, basic_ostream, endl, cout +#include // for shared_ptr, make_shared, make_unique +#include // for scoped_lock +#include // for get + +#include "TrackPlayer.h" // for TrackPlayer + +VSPlayer::VSPlayer(std::shared_ptr handler, + std::shared_ptr vsSink) { + this->handler = handler; + this->vsSink = vsSink; + this->vsSink->state_callback = [this](uint8_t state) { + this->state_callback(state); + }; + + this->handler->trackPlayer->setDataCallback( + [this](uint8_t* data, size_t bytes, size_t trackId, + bool STORAGE_VOLATILE) { + if (!this->track) { + this->track = std::make_shared(trackId, 4098 * 32); + this->vsSink->new_track(this->track); + BELL_LOG(error, "VSPlayer", "New track_id (%d)", trackId); + } + if (trackId != this->track->track_id) { + this->vsSink->soft_stop_feed(); + this->track = std::make_shared(trackId, 4098 * 32); + this->vsSink->new_track(this->track); + BELL_LOG(error, "VSPlayer", "New track_id (%d)", trackId); + } + if (this->vsSink->tracks[0]->track_id != trackId && + (this->vsSink->tracks[0]->state < VS1053_TRACK::tsSoftCancel)) { + this->vsSink->soft_stop_feed(); + BELL_LOG(error, "VSPlayer", + "VSSink track_id (%d) is different from VSPlayer(%d)", + this->vsSink->tracks[0]->track_id, trackId); + } + return this->track->feed_data(data, bytes, STORAGE_VOLATILE); + }, + [this](size_t trackId) { return this->vsSink->track_seekable(trackId); }, + [this](size_t trackId) { + return this->vsSink->spaces_available(trackId); + }); + + this->isPaused = false; + + this->handler->stateCallback = + [this](cspot::DeviceStateHandler::Command event) { + switch (event.commandType) { + case cspot::DeviceStateHandler::CommandType::PAUSE: + if (this->track) + this->vsSink->new_state(this->track->state, + VS1053_TRACK::tsPlaybackPaused); + break; + case cspot::DeviceStateHandler::CommandType::PLAY: + if (this->track) + this->vsSink->new_state(this->track->state, + VS1053_TRACK::tsPlaybackSeekable); + break; + case cspot::DeviceStateHandler::CommandType::DISC: + this->track = nullptr; + this->vsSink->delete_all_tracks(); + this->vsSink->stop_feed(); + //this->currentTrack = nullptr; + this->futureTrack = nullptr; + break; + case cspot::DeviceStateHandler::CommandType::FLUSH: + this->track->empty_feed(); + break; + case cspot::DeviceStateHandler::CommandType::SKIP_NEXT: + [[fallthrough]]; + case cspot::DeviceStateHandler::CommandType::SKIP_PREV: + this->vsSink->stop_feed(); + break; + case cspot::DeviceStateHandler::CommandType::PLAYBACK_START: + if (this->track != nullptr) { + this->track = nullptr; + if (this->currentTrack != nullptr) { + this->vsSink->delete_all_tracks(); + this->futureTrack = nullptr; + } + } + break; + case cspot::DeviceStateHandler::CommandType::PLAYBACK: + this->isPaused = true; + this->playlistEnd = false; + if (this->currentTrack != nullptr) + this->futureTrack = + std::get>(event.data); + else + this->currentTrack = + std::get>(event.data); + break; + case cspot::DeviceStateHandler::CommandType::DEPLETED: + this->track = nullptr; + this->futureTrack = nullptr; + this->vsSink->stop_feed(); + break; + case cspot::DeviceStateHandler::CommandType::VOLUME: { + this->volume = std::get(event.data); + this->vsSink->feed_command([this](uint8_t) { + this->vsSink->set_volume_logarithmic(this->volume); + }); + this->handler->putDeviceState(PutStateReason_PLAYER_STATE_CHANGED); + break; + } + default: + break; + } + }; +} + +void VSPlayer::state_callback(uint8_t state) { + if (state == 1) { + currentTrack->trackMetrics->startTrackPlaying( + currentTrack->requestedPosition); + this->handler->putPlayerState(); + } + if (state == 7) { + currentTrack->trackMetrics->endTrack(); + //this->handler->ctx->playbackMetrics->sendEvent(currentTrack); + if (futureTrack != nullptr) { + currentTrack = futureTrack; + futureTrack = nullptr; + } else { + currentTrack = nullptr; + this->track = nullptr; + } + } +} + +void VSPlayer::disconnect() { + isRunning = false; + std::scoped_lock lock(runningMutex); +} diff --git a/targets/esp32/main/VSPlayer.h b/targets/esp32/main/VSPlayer.h new file mode 100644 index 00000000..f1cad8bb --- /dev/null +++ b/targets/esp32/main/VSPlayer.h @@ -0,0 +1,38 @@ +#pragma once + +#include // for size_t +#include // for uint8_t +#include // for atomic +#include // for shared_ptr, unique_ptr +#include // for mutex +#include // for string + +#include "DeviceStateHandler.h" // for DeviceStateHandler, DeviceStateHandler::CommandType +#include "VS1053.h" +namespace cspot { +class DeviceStateHandler; +} // namespace cspot + +class VSPlayer { + public: + VSPlayer(std::shared_ptr handler, + std::shared_ptr vsSink = NULL); + void disconnect(); + size_t volume = 0; + + private: + size_t trackId = 0; + std::string currentTrackId; + std::shared_ptr vsSink; + std::shared_ptr handler; + std::shared_ptr track = nullptr; + std::shared_ptr futureTrack = nullptr, + currentTrack = nullptr; + void state_callback(uint8_t state); + + std::atomic pauseRequested = false; + std::atomic isPaused = true; + std::atomic isRunning = true; + std::mutex runningMutex; + std::atomic playlistEnd = false; +}; diff --git a/targets/esp32/main/VSinit.h b/targets/esp32/main/VSinit.h new file mode 100644 index 00000000..0ed99e10 --- /dev/null +++ b/targets/esp32/main/VSinit.h @@ -0,0 +1,117 @@ + +#include +#include +#include +#include "esp_log.h" + +#include "VS1053.h" + +#if defined(SD_IN_USE) +#include +#include +#include "esp_vfs_fat.h" +#include "sdmmc_cmd.h" +#define MOUNT_POINT "/sdcard" +#endif +SemaphoreHandle_t SPI_semaphore; +#define TAG "INIT" +void initAudioSink(std::shared_ptr VS1053) { + esp_err_t ret; + // SPI SETUP + spi_bus_config_t bus_cfg; + memset(&bus_cfg, 0, sizeof(spi_bus_config_t)); + bus_cfg.sclk_io_num = CONFIG_GPIO_CLK; + bus_cfg.mosi_io_num = CONFIG_GPIO_MOSI; + bus_cfg.miso_io_num = CONFIG_GPIO_MISO; + bus_cfg.quadwp_io_num = -1; + bus_cfg.quadhd_io_num = -1; + ESP_LOGI("vsInit", "spi config done"); + ret = spi_bus_initialize(HSPI_HOST, &bus_cfg, 1); + assert(ret == ESP_OK); + SPI_semaphore = xSemaphoreCreateMutex(); + + // VS1053 SETUP + VS1053->init(HSPI_HOST, &SPI_semaphore); +#if defined(SD_IN_USE) + if (CONFIG_GPIO_SD_CS >= 0) { + sdspi_device_config_t sd_device = SDSPI_DEVICE_CONFIG_DEFAULT(); + sd_device.gpio_cs = (gpio_num_t)CONFIG_GPIO_SD_CS; + sd_device.gpio_int = (gpio_num_t)-1; + gpio_install_isr_service(0); + sdspi_dev_handle_t sd_spi_handle; + ret = sdspi_host_init(); + ESP_ERROR_CHECK(ret); + ret = sdspi_host_init_device(&sd_device, &sd_spi_handle); + ESP_ERROR_CHECK(ret); + sdmmc_host_t host = SDSPI_HOST_DEFAULT(); + host.slot = sd_spi_handle; + gpio_reset_pin((gpio_num_t)CONFIG_GPIO_SD_CS); + gpio_set_direction((gpio_num_t)CONFIG_GPIO_SD_CS, GPIO_MODE_OUTPUT); + + esp_vfs_fat_sdmmc_mount_config_t mount_config = { +#ifdef CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED + .format_if_mount_failed = true, +#else + .format_if_mount_failed = false, +#endif // EXAMPLE_FORMAT_IF_MOUNT_FAILED + .max_files = 5, + .allocation_unit_size = 16 * 1024}; + ESP_LOGI(TAG, "Initializing SD card"); + /* + ret = esp_vfs_fat_sdspi_mount("/sdcard", &host, &sd_device, &mount_config, &card); + if (ret != ESP_OK) { + if (ret == ESP_FAIL) { + ESP_LOGE(TAG, "Failed to mount filesystem. " + "If you want the card to be formatted, set the CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option."); + } + else { + ESP_LOGE(TAG, "Failed to initialize the card (%s). " + "Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret)); + } + } + */ + sdmmc_card_t* card = (sdmmc_card_t*)malloc(sizeof(sdmmc_card_t)); + + ESP_LOGI(TAG, "Filesystem mounted"); + if (ret == ESP_OK) + sdmmc_card_print_info(stdout, card); + ret = esp_vfs_fat_sdspi_mount("/sdcard", &host, &sd_device, &mount_config, + &card); + if (ret != ESP_OK) { + if (ret == ESP_FAIL) { + ESP_LOGE(TAG, + "Failed to mount filesystem. " + "If you want the card to be formatted, set the " + "CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option."); + } else { + ESP_LOGE(TAG, + "Failed to initialize the card (%s). " + "Make sure SD card lines have pull-up resistors in place.", + esp_err_to_name(ret)); + } + } else { + struct dirent* entry; + struct stat file_stat; + DIR* dir = opendir(MOUNT_POINT); + char n_name[280]; + if (!dir) + printf("no dir\n"); + while ((entry = readdir(dir)) != NULL) { + sprintf(n_name, "%s/%s", MOUNT_POINT, entry->d_name); + printf("%s\n", n_name); + printf("name:%s, ino: %i\n", entry->d_name, entry->d_ino); + printf("stat_return_value:%i\n", stat(n_name, &file_stat)); + printf("stat_mode:%lu\n", file_stat.st_mode); + } + dir = opendir(MOUNT_POINT "/TRACKS"); + if (!dir) + printf("no dir\n"); + while ((entry = readdir(dir)) != NULL) { + printf("%s\n", entry->d_name); + } + closedir(dir); + } + } +#endif + VS1053->write_register(SCI_VOL, 10 | 10 << 8); +} \ No newline at end of file diff --git a/targets/esp32/main/main.cpp b/targets/esp32/main/main.cpp index 8e518803..9e3b39b7 100644 --- a/targets/esp32/main/main.cpp +++ b/targets/esp32/main/main.cpp @@ -7,14 +7,16 @@ #include #include #include "BellHTTPServer.h" +#include "BellLogger.h" // for setDefaultLogger, AbstractLogger #include "BellTask.h" +#include "WrappedSemaphore.h" #include "civetweb.h" #include "esp_event.h" -#include "esp_log.h" #include "esp_spiffs.h" #include "esp_system.h" #include "esp_wifi.h" #include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" #include "freertos/task.h" #include "mdns.h" #include "nvs_flash.h" @@ -23,21 +25,37 @@ #include #include -#include #include -#include "BellTask.h" -#include "CircularBuffer.h" #include "BellUtils.h" -#include "ES8311AudioSink.h" -#include "ESPStatusLed.h" #include "Logger.h" -#include "freertos/ringbuf.h" -#include "freertos/task.h" +#include "esp_log.h" + +#include "lwip/err.h" +#include "lwip/sys.h" + +/* FreeRTOS event group to signal when we are connected*/ +static EventGroupHandle_t s_wifi_event_group; + +/* The event group allows multiple bits for each event, but we only care about two events: + * - we are connected to the AP with an IP + * - we failed to connect after the maximum amount of retries */ +#define WIFI_CONNECTED_BIT BIT0 +#define WIFI_FAIL_BIT BIT1 + +//#define EXAMPLE_ESP_WIFI_SSID CONFIG_EXAMPLE_WIFI_SSID +//#define EXAMPLE_ESP_WIFI_PASS CONFIG_EXAMPLE_WIFI_PASSWORD +#define WIFI_AP_MAXIMUM_RETRY 5 #define DEVICE_NAME CONFIG_CSPOT_DEVICE_NAME +#ifdef CONFIG_BELL_NOCODEC +#include "VSPlayer.h" +#include "VSinit.h" +#else +#define TAG "INIT" +#include "EspPlayer.h" #ifdef CONFIG_CSPOT_SINK_INTERNAL #include #endif @@ -56,290 +74,232 @@ #ifdef CONFIG_CSPOT_SINK_TAS5711 #include #endif - -static const char* TAG = "cspot"; - -std::shared_ptr statusLed; -std::string credentialsFileName = "/spiffs/authBlob.json"; -bool createdFromZeroconf = false; +#endif extern "C" { void app_main(void); } -class CSpotPlayer : public bell::Task { - private: - std::shared_ptr handler; - std::unique_ptr audioSink; - std::unique_ptr circularBuffer; - std::atomic isPaused; +static int s_retry_num = 0; +class ZeroconfAuthenticator { public: - CSpotPlayer(std::shared_ptr handler) - : bell::Task("cspot", 8 * 1024, 0, 0) { - this->handler = handler; - this->audioSink = std::make_unique(); - this->audioSink->setParams(44100, 2, 16); - this->audioSink->volumeChanged(160); - - this->circularBuffer = - std::make_unique(1024 * 128 * 8); - - this->handler->getTrackPlayer()->setDataCallback( - [this](uint8_t* data, size_t bytes) { this->feedData(data, bytes); }); - this->isPaused = false; - - this->handler->setEventHandler( - [this](std::unique_ptr event) { - switch (event->eventType) { - case cspot::SpircHandler::EventType::PLAY_PAUSE: - this->isPaused = std::get(event->data); - break; - case cspot::SpircHandler::EventType::FLUSH: - this->circularBuffer->emptyBuffer(); - break; - case cspot::SpircHandler::EventType::SEEK: - this->circularBuffer->emptyBuffer(); - break; - case cspot::SpircHandler::EventType::PLAYBACK_START: - this->circularBuffer->emptyBuffer(); - default: - break; - } - }); - startTask(); - } + ZeroconfAuthenticator(){}; + ~ZeroconfAuthenticator(){}; - void feedData(uint8_t* data, size_t len) { - size_t toWrite = len; + // Authenticator state + int serverPort = 7864; - while (toWrite > 0) { - size_t written = - this->circularBuffer->write(data + (len - toWrite), toWrite); - if (written == 0) { - BELL_SLEEP_MS(10); - } + // Use bell's HTTP server to handle the authentication, although anything can be used + std::unique_ptr server; + std::unique_ptr mdnsService; + std::shared_ptr blob; - toWrite -= written; - } + std::function onAuthSuccess; + std::function onClose; + + void registerMdnsService() { + this->mdnsService = bell::MDNSService::registerService( + blob->getDeviceName(), "_spotify-connect", "_tcp", "", serverPort, + {{"VERSION", "1.0"}, {"CPath", "/spotify_info"}, {"Stack", "SP"}}); } - void runTask() { - std::vector outBuf = std::vector(1024); + void registerHandlers() { + this->server = std::make_unique(serverPort); + + server->registerGet("/spotify_info", [this](struct mg_connection* conn) { + return this->server->makeJsonResponse(this->blob->buildZeroconfInfo()); + }); + + server->registerGet("/close", [this](struct mg_connection* conn) { + CSPOT_LOG(info, "Closing connection"); + this->onClose(); + return this->server->makeEmptyResponse(); + }); + + server->registerPost("/spotify_info", [this](struct mg_connection* conn) { + nlohmann::json obj; + // Prepare a success response for spotify + obj["status"] = 101; + obj["spotifyError"] = 0; + obj["statusString"] = "ERROR-OK"; + + std::string body = ""; + auto requestInfo = mg_get_request_info(conn); + if (requestInfo->content_length > 0) { + body.resize(requestInfo->content_length); + mg_read(conn, body.data(), requestInfo->content_length); + + mg_header hd[10]; + int num = mg_split_form_urlencoded(body.data(), hd, 10); + std::map queryMap; + + // Parse the form data + for (int i = 0; i < num; i++) { + queryMap[hd[i].name] = hd[i].value; + } + if (1) { //queryMap["userName"] != blob->getUserName()) { - while (true) { - if (!this->isPaused) { - size_t read = this->circularBuffer->read(outBuf.data(), outBuf.size()); - this->audioSink->feedPCMFrames(outBuf.data(), read); + CSPOT_LOG(info, "Received zeroauth POST data"); - if (read == 0) { - BELL_SLEEP_MS(100); + // Pass user's credentials to the blob + blob->loadZeroconfQuery(queryMap); + + // We have the blob, proceed to login +#ifndef CONFIG_CSPOT_DISCOVERY_MODE_OPEN + mdnsService->unregisterService(); +#else + onClose(); +#endif + onAuthSuccess(); + } else { + CSPOT_LOG(debug, "User already logged in, skipping auth"); } - } else { - BELL_SLEEP_MS(100); } - } + + return server->makeJsonResponse(obj.dump()); + }); + + // Register mdns service, for spotify to find us + this->registerMdnsService(); + std::cout << "Waiting for spotify app to connect..." << std::endl; } }; class CSpotTask : public bell::Task { - public: - CSpotTask() : bell::Task("cspot", 32 * 1024, 0, 1) { startTask(); } + private: + //std::unique_ptr handler; +#ifndef CONFIG_BELL_NOCODEC + std::shared_ptr audioSink; +#endif + std::unique_ptr zeroconfServer; + public: + CSpotTask() : bell::Task("cspot", 16 * 1024, 0, 0) { + startTask(); + } void runTask() { + mdns_init(); mdns_hostname_set("cspot"); - std::atomic gotBlob = false; - - auto blob = std::make_shared(DEVICE_NAME); - - auto server = std::make_unique(8080); - server->registerGet( - "/spotify_info", [&server, blob](struct mg_connection* conn) { - return server->makeJsonResponse(blob->buildZeroconfInfo()); - }); - server->registerPost( - "/spotify_info", [&server, blob, &gotBlob](struct mg_connection* conn) { - nlohmann::json obj; - obj["status"] = 101; - obj["spotifyError"] = 0; - obj["statusString"] = "ERROR-OK"; - - std::string body = ""; - auto requestInfo = mg_get_request_info(conn); - if (requestInfo->content_length > 0) { - body.resize(requestInfo->content_length); - mg_read(conn, body.data(), requestInfo->content_length); - - mg_header hd[10]; - int num = mg_split_form_urlencoded(body.data(), hd, 10); - std::map queryMap; - - for (int i = 0; i < num; i++) { - queryMap[hd[i].name] = hd[i].value; - } - - blob->loadZeroconfQuery(queryMap); - gotBlob = true; - } +#ifdef CONFIG_BELL_NOCODEC + std::shared_ptr audioSink; + audioSink = std::make_shared(); + initAudioSink(audioSink); +#else +#ifdef CONFIG_CSPOT_SINK_INTERNAL + auto audioSink = std::make_shared(); +#endif +#ifdef CONFIG_CSPOT_SINK_AC101 + auto audioSink = std::make_shared(); +#endif +#ifdef CONFIG_CSPOT_SINK_ES8388 + auto audioSink = std::make_shared(); +#endif +#ifdef CONFIG_CSPOT_SINK_ES9018 + auto audioSink = std::make_shared(); +#endif +#ifdef CONFIG_CSPOT_SINK_PCM5102 + auto audioSink = std::make_shared(); +#endif +#ifdef CONFIG_CSPOT_SINK_TAS5711 + auto audioSink = std::make_shared(); +#endif + audioSink->setParams(44100, 2, 16); + audioSink->volumeChanged(160); +#endif - return server->makeJsonResponse(obj.dump()); - }); + auto loggedInSemaphore = std::make_shared(); - bell::MDNSService::registerService( - blob->getDeviceName(), "_spotify-connect", "_tcp", "", 8080, - {{"VERSION", "1.0"}, {"CPath", "/spotify_info"}, {"Stack", "SP"}}); + std::atomic isRunningInDiscoveryMode = true; + std::atomic isRunning = true; + this->zeroconfServer = std::make_unique(); - while (!gotBlob) { - BELL_SLEEP_MS(1000); - BELL_LOG(info, "cspot", "Waiting for spotify app to connect..."); - } + auto loginBlob = std::make_shared(DEVICE_NAME); - BELL_LOG(info, "cspot", "Got blob!"); - if (gotBlob) { - auto ctx = cspot::Context::createFromBlob(blob); - CSPOT_LOG(info, "Creating player"); - ctx->session->connectWithRandomAp(); - auto token = ctx->session->authenticate(blob); - - // Auth successful - if (token.size() > 0) { - ctx->session->startTask(); - auto handler = std::make_shared(ctx); - handler->subscribeToMercury(); - auto player = std::make_shared(handler); - - while (true) { - ctx->session->handlePacket(); - } + this->zeroconfServer->onClose = [this, &isRunning, &loginBlob]() { + isRunning = false; +#ifndef CONFIG_CSPOT_DISCOVERY_MODE_OPEN + CSPOT_LOG(info, "Waiting for spotify app to connect..."); + loginBlob = std::make_shared(DEVICE_NAME); + this->zeroconfServer->blob = loginBlob; + this->zeroconfServer->registerMdnsService(); +#endif + }; + +#ifdef CONFIG_CSPOT_LOGIN_PASS + loginBlob->loadUserPass(CONFIG_CSPOT_LOGIN_USERNAME, + CONFIG_CSPOT_LOGIN_PASSWORD); + loggedInSemaphore->give(); + +#else + zeroconfServer->blob = loginBlob; + zeroconfServer->onAuthSuccess = [loggedInSemaphore, &isRunning]() { + if (!isRunning) + loggedInSemaphore->give(); + }; + zeroconfServer->registerHandlers(); +#endif + while (true) { + loggedInSemaphore->wait(); + isRunning = true; + auto ctx = cspot::Context::createFromBlob(loginBlob); + CSPOTConnecting:; + try { + ctx->session->connectWithRandomAp(); + ctx->config.authData = ctx->session->authenticate(loginBlob); + if (ctx->config.authData.size() > 0) { + // when credentials file is set, then store reusable credentials + + // Start device handler task + auto handler = std::make_shared( + ctx, zeroconfServer->onClose); + + // Start handling mercury messages + ctx->session->startTask(); + + // Create a player, pass the handler +#ifndef CONFIG_BELL_NOCODEC + auto player = std::make_shared(audioSink, handler); +#else + auto player = std::make_shared(handler, audioSink); +#endif + // If we wanted to handle multiple devices, we would halt this loop + // when a new zeroconf login is requested, and reinitialize the session + uint8_t taskCount = 0; + while (isRunning) { + ctx->session->handlePacket(); + } - handler->disconnect(); - // player->disconnect(); + // Never happens, but required for above case + handler->disconnect(); + player->disconnect(); + } else { + std::cout << "Failed to authenticate" << std::endl; + } + } catch (std::exception& e) { + std::cout << "Error while connecting " << e.what() << std::endl; + goto CSPOTConnecting; } } } }; -static void cspotTask(void* pvParameters) { - - // #ifdef CONFIG_CSPOT_SINK_INTERNAL - // auto audioSink = std::make_shared(); - // #endif - // #ifdef CONFIG_CSPOT_SINK_AC101 - // auto audioSink = std::make_shared(); - // #endif - // #ifdef CONFIG_CSPOT_SINK_ES8388 - // auto audioSink = std::make_shared(); - // #endif - // #ifdef CONFIG_CSPOT_SINK_ES9018 - // auto audioSink = std::make_shared(); - // #endif - // #ifdef CONFIG_CSPOT_SINK_PCM5102 - // auto audioSink = std::make_shared(); - // #endif - // #ifdef CONFIG_CSPOT_SINK_TAS5711 - // auto audioSink = std::make_shared(); - // #endif - - // // Config file - // file = std::make_shared(); - // configMan = std::make_shared("/spiffs/config.json", file); - - // if (!configMan->load()) { - // CSPOT_LOG(error, "Config error"); - // } - - // configMan->deviceName = DEVICE_NAME; - // #ifdef CONFIG_CSPOT_QUALITY_96 - // configMan->format = AudioFormat_OGG_VORBIS_96; - // #endif - // #ifdef CONFIG_CSPOT_QUALITY_160 - // configMan->format = AudioFormat_OGG_VORBIS_160; - // #endif - // #ifdef CONFIG_CSPOT_QUALITY_320 - // configMan->format = AudioFormat_OGG_VORBIS_320; - // #endif - - // auto createPlayerCallback = [audioSink](std::shared_ptr blob) { - - // // heap_trace_start(HEAP_TRACE_LEAKS); - // // esp_dump_per_task_heap_info(); - - // CSPOT_LOG(info, "Creating player"); - // statusLed->setStatus(StatusLed::SPOT_INITIALIZING); - - // auto session = std::make_unique(); - // session->connectWithRandomAp(); - // auto token = session->authenticate(blob); - - // // Auth successful - // if (token.size() > 0) - // { - // if (createdFromZeroconf) { - // file->writeFile(credentialsFileName, blob->toJson()); - // } - - // statusLed->setStatus(StatusLed::SPOT_READY); - - // mercuryManager = std::make_shared(std::move(session)); - // mercuryManager->startTask(); - - // spircController = std::make_shared(mercuryManager, blob->username, audioSink); - - // spircController->setEventHandler([](CSpotEvent& event) { - // switch (event.eventType) { - // case CSpotEventType::TRACK_INFO: - // CSPOT_LOG(info, "Track Info"); - // break; - // case CSpotEventType::PLAY_PAUSE: - // CSPOT_LOG(info, "Track Pause"); - // break; - // case CSpotEventType::SEEK: - // CSPOT_LOG(info, "Track Seek"); - // break; - // case CSpotEventType::DISC: - // CSPOT_LOG(info, "Disconnect"); - // spircController->stopPlayer(); - // mercuryManager->stop(); - // break; - // case CSpotEventType::PREV: - // CSPOT_LOG(info, "Track Previous"); - // break; - // case CSpotEventType::NEXT: - // CSPOT_LOG(info, "Track Next"); - // break; - // default: - // break; - // } - // }); - - // mercuryManager->reconnectedCallback = []() { - // return spircController->subscribe(); - // }; - - // mercuryManager->handleQueue(); - - // mercuryManager.reset(); - // spircController.reset(); - // } - - // BELL_SLEEP_MS(10000); - // // heap_trace_stop(); - // // heap_trace_dump(); - // ESP_LOGI(TAG, "Player exited"); - // auto memUsage = heap_caps_get_free_size(MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); - // auto memUsage2 = heap_caps_get_free_size(MALLOC_CAP_DMA | MALLOC_CAP_8BIT); - - // BELL_LOG(info, "esp32", "Free RAM %d | %d", memUsage, memUsage2); - // }; - - // createdFromZeroconf = true; - // auto httpServer = std::make_shared(2137); - // auto authenticator = std::make_shared(createPlayerCallback, httpServer); - // authenticator->registerHandlers(); - // httpServer->listen(); - - vTaskSuspend(NULL); +static void event_handler(void* arg, esp_event_base_t event_base, + int32_t event_id, void* event_data) { + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { + esp_wifi_connect(); + } else if (event_base == WIFI_EVENT && + event_id == WIFI_EVENT_STA_DISCONNECTED) { + esp_wifi_connect(); + s_retry_num++; + ESP_LOGI(TAG, "retry to connect to the AP"); + } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { + ip_event_got_ip_t* event = (ip_event_got_ip_t*)event_data; + ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip)); + s_retry_num = 0; + xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); + } } void init_spiffs() { @@ -352,11 +312,12 @@ void init_spiffs() { if (ret != ESP_OK) { if (ret == ESP_FAIL) { - ESP_LOGE(TAG, "Failed to mount or format filesystem"); + ESP_LOGE("SPIFFS", "Failed to mount or format filesystem"); } else if (ret == ESP_ERR_NOT_FOUND) { - ESP_LOGE(TAG, "Failed to find SPIFFS partition"); + ESP_LOGE("SPIFFS", "Failed to find SPIFFS partition"); } else { - ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret)); + ESP_LOGE("SPIFFS", "Failed to initialize SPIFFS (%s)", + esp_err_to_name(ret)); } return; } @@ -364,10 +325,57 @@ void init_spiffs() { size_t total = 0, used = 0; ret = esp_spiffs_info(conf.partition_label, &total, &used); if (ret != ESP_OK) { - ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)", + ESP_LOGE("SPIFFS", "Failed to get SPIFFS partition information (%s)", esp_err_to_name(ret)); } else { - ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used); + ESP_LOGE("SPIFFS", "Partition size: total: %d, used: %d", total, used); + } +} + +void wifi_init_sta(void) { + s_wifi_event_group = xEventGroupCreate(); + + ESP_ERROR_CHECK(esp_netif_init()); + + ESP_ERROR_CHECK(esp_event_loop_create_default()); + esp_netif_create_default_wifi_sta(); + + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + esp_event_handler_instance_t instance_any_id; + esp_event_handler_instance_t instance_got_ip; + ESP_ERROR_CHECK(esp_event_handler_instance_register( + WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, &instance_any_id)); + ESP_ERROR_CHECK(esp_event_handler_instance_register( + IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, &instance_got_ip)); + wifi_config_t wifi_config = {}; + strcpy(reinterpret_cast(wifi_config.sta.ssid), + CONFIG_EXAMPLE_WIFI_SSID); + strcpy(reinterpret_cast(wifi_config.sta.password), + CONFIG_EXAMPLE_WIFI_PASSWORD); + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config)); + ESP_ERROR_CHECK(esp_wifi_start()); + + ESP_LOGI(TAG, "wifi_init_sta finished."); + + /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum + * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */ + EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, + WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, + pdFALSE, pdFALSE, portMAX_DELAY); + + /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually + * happened. */ + if (bits & WIFI_CONNECTED_BIT) { + ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", + CONFIG_EXAMPLE_WIFI_SSID, CONFIG_EXAMPLE_WIFI_SSID); + } else if (bits & WIFI_FAIL_BIT) { + ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", + CONFIG_EXAMPLE_WIFI_SSID, CONFIG_EXAMPLE_WIFI_SSID); + } else { + ESP_LOGE(TAG, "UNEXPECTED EVENT"); } } @@ -383,22 +391,16 @@ void app_main(void) { } ESP_ERROR_CHECK(ret); - init_spiffs(); - - // statusLed->setStatus(StatusLed::WIFI_CONNECTING); - - esp_wifi_set_ps(WIFI_PS_NONE); - ESP_ERROR_CHECK(esp_netif_init()); - ESP_ERROR_CHECK(esp_event_loop_create_default()); - ESP_ERROR_CHECK(example_connect()); + //init_spiffs(); + wifi_init_sta(); // statusLed->setStatus(StatusLed::WIFI_CONNECTED); - ESP_LOGI(TAG, "Connected to AP, start spotify receiver"); + ESP_LOGI("MAIN", "Connected to AP, start spotify receiver"); //auto taskHandle = xTaskCreatePinnedToCore(&cspotTask, "cspot", 12*1024, NULL, 5, NULL, 1); /*auto taskHandle = */ bell::setDefaultLogger(); - + //bell::enableTimestampLogging(); auto task = std::make_unique(); vTaskSuspend(NULL); } diff --git a/targets/esp32/sdkconfig.defaults b/targets/esp32/sdkconfig.defaults index e7db07f6..3cd924f3 100644 --- a/targets/esp32/sdkconfig.defaults +++ b/targets/esp32/sdkconfig.defaults @@ -4,14 +4,14 @@ # CONFIG_IDF_CMAKE=y CONFIG_IDF_TARGET_ARCH_XTENSA=y -CONFIG_IDF_TARGET="esp32s3" -CONFIG_IDF_TARGET_ESP32S3=y -CONFIG_IDF_FIRMWARE_CHIP_ID=0x0009 +CONFIG_IDF_TARGET="esp32" +CONFIG_IDF_TARGET_ESP32=y +CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000 # # SDK tool configuration # -CONFIG_SDK_TOOLPREFIX="xtensa-esp32s3-elf-" +CONFIG_SDK_TOOLPREFIX="xtensa-esp32-elf-" # CONFIG_SDK_TOOLCHAIN_SUPPORTS_TIME_WIDE_64_BITS is not set # end of SDK tool configuration @@ -38,7 +38,6 @@ CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16 # # Bootloader config # -CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x0 CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y # CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set # CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set @@ -90,27 +89,26 @@ CONFIG_BOOT_ROM_LOG_ALWAYS_ON=y # CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=115200 # CONFIG_ESPTOOLPY_NO_STUB is not set -# CONFIG_ESPTOOLPY_OCT_FLASH is not set # CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set # CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set CONFIG_ESPTOOLPY_FLASHMODE_DIO=y # CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR=y CONFIG_ESPTOOLPY_FLASHMODE="dio" -# CONFIG_ESPTOOLPY_FLASHFREQ_120M is not set CONFIG_ESPTOOLPY_FLASHFREQ_80M=y # CONFIG_ESPTOOLPY_FLASHFREQ_40M is not set +# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set # CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set CONFIG_ESPTOOLPY_FLASHFREQ="80m" # CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set -# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set -CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set -CONFIG_ESPTOOLPY_FLASHSIZE="8MB" +CONFIG_ESPTOOLPY_FLASHSIZE="4MB" CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y CONFIG_ESPTOOLPY_BEFORE_RESET=y # CONFIG_ESPTOOLPY_BEFORE_NORESET is not set @@ -130,6 +128,7 @@ CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER_VAL=115200 CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 # end of Serial flasher config + # # Partition Table # @@ -554,115 +553,155 @@ CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y # end of ESP-TLS # -# ESP32S3-Specific +# ESP32-specific # -# CONFIG_ESP32S3_DEFAULT_CPU_FREQ_80 is not set -# CONFIG_ESP32S3_DEFAULT_CPU_FREQ_160 is not set -CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y -CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ=240 - -# -# Cache config -# -CONFIG_ESP32S3_INSTRUCTION_CACHE_16KB=y -# CONFIG_ESP32S3_INSTRUCTION_CACHE_32KB is not set -CONFIG_ESP32S3_INSTRUCTION_CACHE_SIZE=0x4000 -# CONFIG_ESP32S3_INSTRUCTION_CACHE_4WAYS is not set -CONFIG_ESP32S3_INSTRUCTION_CACHE_8WAYS=y -CONFIG_ESP32S3_ICACHE_ASSOCIATED_WAYS=8 -# CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_16B is not set -CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_32B=y -CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_SIZE=32 -# CONFIG_ESP32S3_INSTRUCTION_CACHE_WRAP is not set -# CONFIG_ESP32S3_DATA_CACHE_16KB is not set -CONFIG_ESP32S3_DATA_CACHE_32KB=y -# CONFIG_ESP32S3_DATA_CACHE_64KB is not set -CONFIG_ESP32S3_DATA_CACHE_SIZE=0x8000 -# CONFIG_ESP32S3_DATA_CACHE_4WAYS is not set -CONFIG_ESP32S3_DATA_CACHE_8WAYS=y -CONFIG_ESP32S3_DCACHE_ASSOCIATED_WAYS=8 -# CONFIG_ESP32S3_DATA_CACHE_LINE_16B is not set -CONFIG_ESP32S3_DATA_CACHE_LINE_32B=y -# CONFIG_ESP32S3_DATA_CACHE_LINE_64B is not set -CONFIG_ESP32S3_DATA_CACHE_LINE_SIZE=32 -# CONFIG_ESP32S3_DATA_CACHE_WRAP is not set -# end of Cache config - -CONFIG_ESP32S3_SPIRAM_SUPPORT=y +CONFIG_ESP32_REV_MIN_0=y +# CONFIG_ESP32_REV_MIN_1 is not set +# CONFIG_ESP32_REV_MIN_2 is not set +# CONFIG_ESP32_REV_MIN_3 is not set +CONFIG_ESP32_REV_MIN=0 +CONFIG_ESP32_DPORT_WORKAROUND=y +# CONFIG_ESP32_DEFAULT_CPU_FREQ_80 is not set +# CONFIG_ESP32_DEFAULT_CPU_FREQ_160 is not set +CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y +CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240 +CONFIG_ESP32_SPIRAM_SUPPORT=y # # SPI RAM config # -CONFIG_SPIRAM_MODE_QUAD=y -# CONFIG_SPIRAM_MODE_OCT is not set CONFIG_SPIRAM_TYPE_AUTO=y -# CONFIG_SPIRAM_TYPE_ESPPSRAM16 is not set # CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set # CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set CONFIG_SPIRAM_SIZE=-1 - -# -# PSRAM Clock and CS IO for ESP32S3 -# -CONFIG_DEFAULT_PSRAM_CLK_IO=30 -CONFIG_DEFAULT_PSRAM_CS_IO=26 -# end of PSRAM Clock and CS IO for ESP32S3 - -# CONFIG_SPIRAM_FETCH_INSTRUCTIONS is not set -# CONFIG_SPIRAM_RODATA is not set -CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=y -# CONFIG_SPIRAM_SPEED_120M is not set -CONFIG_SPIRAM_SPEED_80M=y # CONFIG_SPIRAM_SPEED_40M is not set +CONFIG_SPIRAM_SPEED_80M=y CONFIG_SPIRAM=y CONFIG_SPIRAM_BOOT_INIT=y -# CONFIG_SPIRAM_IGNORE_NOTFOUND is not set # CONFIG_SPIRAM_USE_MEMMAP is not set # CONFIG_SPIRAM_USE_CAPS_ALLOC is not set CONFIG_SPIRAM_USE_MALLOC=y CONFIG_SPIRAM_MEMTEST=y -CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=16384 -CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y -CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=32768 +CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=256 +# CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP is not set +CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=65536 +CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y +CONFIG_SPIRAM_CACHE_WORKAROUND=y + +# +# SPIRAM cache workaround debugging +# +CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_MEMW=y +# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST is not set +# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_NOPS is not set +# end of SPIRAM cache workaround debugging + +CONFIG_SPIRAM_BANKSWITCH_ENABLE=y +CONFIG_SPIRAM_BANKSWITCH_RESERVE=8 +CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=y +# CONFIG_SPIRAM_OCCUPY_HSPI_HOST is not set +CONFIG_SPIRAM_OCCUPY_VSPI_HOST=y +# CONFIG_SPIRAM_OCCUPY_NO_HOST is not set + +# +# PSRAM clock and cs IO for ESP32-DOWD +# +CONFIG_D0WD_PSRAM_CLK_IO=17 +CONFIG_D0WD_PSRAM_CS_IO=16 +# end of PSRAM clock and cs IO for ESP32-DOWD + +# +# PSRAM clock and cs IO for ESP32-D2WD +# +CONFIG_D2WD_PSRAM_CLK_IO=9 +CONFIG_D2WD_PSRAM_CS_IO=10 +# end of PSRAM clock and cs IO for ESP32-D2WD + +# +# PSRAM clock and cs IO for ESP32-PICO +# +CONFIG_PICO_PSRAM_CS_IO=10 +# end of PSRAM clock and cs IO for ESP32-PICO + +# CONFIG_SPIRAM_2T_MODE is not set # end of SPI RAM config -# CONFIG_ESP32S3_TRAX is not set -CONFIG_ESP32S3_TRACEMEM_RESERVE_DRAM=0x0 -# CONFIG_ESP32S3_ULP_COPROC_ENABLED is not set -CONFIG_ESP32S3_ULP_COPROC_RESERVE_MEM=0 -CONFIG_ESP32S3_DEBUG_OCDAWARE=y -CONFIG_ESP32S3_BROWNOUT_DET=y -CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_7=y -# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_6 is not set -# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_5 is not set -# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_4 is not set -# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_3 is not set -# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_2 is not set -# CONFIG_ESP32S3_BROWNOUT_DET_LVL_SEL_1 is not set -CONFIG_ESP32S3_BROWNOUT_DET_LVL=7 -CONFIG_ESP32S3_TIME_SYSCALL_USE_RTC_FRC1=y -# CONFIG_ESP32S3_TIME_SYSCALL_USE_RTC is not set -# CONFIG_ESP32S3_TIME_SYSCALL_USE_FRC1 is not set -# CONFIG_ESP32S3_TIME_SYSCALL_USE_NONE is not set -CONFIG_ESP32S3_RTC_CLK_SRC_INT_RC=y -# CONFIG_ESP32S3_RTC_CLK_SRC_EXT_CRYS is not set -# CONFIG_ESP32S3_RTC_CLK_SRC_EXT_OSC is not set -# CONFIG_ESP32S3_RTC_CLK_SRC_INT_8MD256 is not set -CONFIG_ESP32S3_RTC_CLK_CAL_CYCLES=1024 -CONFIG_ESP32S3_DEEP_SLEEP_WAKEUP_DELAY=2000 -# CONFIG_ESP32S3_RTCDATA_IN_FAST_MEM is not set -# CONFIG_ESP32S3_USE_FIXED_STATIC_RAM_SIZE is not set -# end of ESP32S3-Specific +# CONFIG_ESP32_TRAX is not set +CONFIG_ESP32_TRACEMEM_RESERVE_DRAM=0x0 +# CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set +CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR=y +CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES=4 +# CONFIG_ESP32_ULP_COPROC_ENABLED is not set +CONFIG_ESP32_ULP_COPROC_RESERVE_MEM=0 +CONFIG_ESP32_DEBUG_OCDAWARE=y +CONFIG_ESP32_BROWNOUT_DET=y +CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_0=y +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_1 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_2 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_3 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_4 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_5 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_6 is not set +# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_7 is not set +CONFIG_ESP32_BROWNOUT_DET_LVL=0 +CONFIG_ESP32_REDUCE_PHY_TX_POWER=y +CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y +# CONFIG_ESP32_TIME_SYSCALL_USE_RTC is not set +# CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 is not set +# CONFIG_ESP32_TIME_SYSCALL_USE_NONE is not set +CONFIG_ESP32_RTC_CLK_SRC_INT_RC=y +# CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS is not set +# CONFIG_ESP32_RTC_CLK_SRC_EXT_OSC is not set +# CONFIG_ESP32_RTC_CLK_SRC_INT_8MD256 is not set +CONFIG_ESP32_RTC_CLK_CAL_CYCLES=1024 +CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY=2000 +CONFIG_ESP32_XTAL_FREQ_40=y +# CONFIG_ESP32_XTAL_FREQ_26 is not set +# CONFIG_ESP32_XTAL_FREQ_AUTO is not set +CONFIG_ESP32_XTAL_FREQ=40 +# CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE is not set +# CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set +# CONFIG_ESP32_USE_FIXED_STATIC_RAM_SIZE is not set +CONFIG_ESP32_DPORT_DIS_INTERRUPT_LVL=5 +# end of ESP32-specific # # ADC-Calibration # # end of ADC-Calibration + # # Common ESP-related # CONFIG_ESP_ERR_TO_NAME_LOOKUP=y +CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32 +CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304 +CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192 +CONFIG_ESP_IPC_TASK_STACK_SIZE=1024 +CONFIG_ESP_IPC_USES_CALLERS_PRIORITY=y +CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048 +CONFIG_ESP_CONSOLE_UART_DEFAULT=y +# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set +# CONFIG_ESP_CONSOLE_UART_NONE is not set +CONFIG_ESP_CONSOLE_UART_NUM=0 +CONFIG_ESP_CONSOLE_UART_TX_GPIO=1 +CONFIG_ESP_CONSOLE_UART_RX_GPIO=3 +CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200 +CONFIG_ESP_INT_WDT=y +CONFIG_ESP_INT_WDT_TIMEOUT_MS=800 +CONFIG_ESP_INT_WDT_CHECK_CPU1=y +CONFIG_ESP_TASK_WDT=y +# CONFIG_ESP_TASK_WDT_PANIC is not set +CONFIG_ESP_TASK_WDT_TIMEOUT_S=5 +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=y +# CONFIG_ESP_PANIC_HANDLER_IRAM is not set +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y +CONFIG_ESP_MAC_ADDR_UNIVERSE_BT_OFFSET=2 +CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y # end of Common ESP-related # @@ -1090,7 +1129,7 @@ CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y CONFIG_LWIP_TIMERS_ONDEMAND=y CONFIG_LWIP_MAX_SOCKETS=16 # CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set -# CONFIG_LWIP_SO_LINGER is not set +CONFIG_LWIP_SO_LINGER=y CONFIG_LWIP_SO_REUSE=y CONFIG_LWIP_SO_REUSE_RXTOALL=y # CONFIG_LWIP_SO_RCVBUF is not set