[
  {
    "path": ".gitattributes",
    "content": "###############################################################################\n# Set default behavior to automatically normalize line endings.\n###############################################################################\n* text=auto\n\n###############################################################################\n# Set default behavior for command prompt diff.\n#\n# This is need for earlier builds of msysgit that does not have it on by\n# default for csharp files.\n# Note: This is only used by command line\n###############################################################################\n#*.cs     diff=csharp\n\n###############################################################################\n# Set the merge driver for project and solution files\n#\n# Merging from the command prompt will add diff markers to the files if there\n# are conflicts (Merging from VS is not affected by the settings below, in VS\n# the diff markers are never inserted). Diff markers may cause the following \n# file extensions to fail to load in VS. An alternative would be to treat\n# these files as binary and thus will always conflict and require user\n# intervention with every merge. To do so, just uncomment the entries below\n###############################################################################\n#*.sln       merge=binary\n#*.csproj    merge=binary\n#*.vbproj    merge=binary\n#*.vcxproj   merge=binary\n#*.vcproj    merge=binary\n#*.dbproj    merge=binary\n#*.fsproj    merge=binary\n#*.lsproj    merge=binary\n#*.wixproj   merge=binary\n#*.modelproj merge=binary\n#*.sqlproj   merge=binary\n#*.wwaproj   merge=binary\n\n###############################################################################\n# behavior for image files\n#\n# image files are treated as binary by default.\n###############################################################################\n#*.jpg   binary\n#*.png   binary\n#*.gif   binary\n\n###############################################################################\n# diff behavior for common document formats\n# \n# Convert binary document formats to text before diffing them. This feature\n# is only available from the command line. Turn it on by uncommenting the \n# entries below.\n###############################################################################\n#*.doc   diff=astextplain\n#*.DOC   diff=astextplain\n#*.docx  diff=astextplain\n#*.DOCX  diff=astextplain\n#*.dot   diff=astextplain\n#*.DOT   diff=astextplain\n#*.pdf   diff=astextplain\n#*.PDF   diff=astextplain\n#*.rtf   diff=astextplain\n#*.RTF   diff=astextplain\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: \"[BUG]\"\nlabels: bug\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Desktop (please complete the following information):**\n - OS: [e.g. iOS]\n - Browser [e.g. chrome, safari]\n - Version [e.g. 22]\n\n**Midi device:**\n - e.g. Behringer XTouch Mini\n - e.g. Korg NanoControl\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: \"[feature]\"\nlabels: enhancement\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User-specific files\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n\n# Visual Studio 2015 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUNIT\n*.VisualState.xml\nTestResult.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# DNX\nproject.lock.json\nproject.fragment.lock.json\nartifacts/\n\n*_i.c\n*_p.c\n*_i.h\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding add-in\n.JustCode\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# TODO: Comment the next line if you want to checkin your web deploy settings\n# but database connection strings (with potential passwords) will be unencrypted\n#*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n*.nupkg\n# The packages folder can be ignored because of Package Restore\n**/packages/*\n# except build/, which is used as an MSBuild target.\n!**/packages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/packages/repositories.config\n# NuGet v3's project.json files produces more ignoreable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.jfm\n*.pfx\n*.publishsettings\nnode_modules/\norleans.codegen.cs\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\n\n# SQL Server files\n*.mdf\n*.ldf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# JetBrains Rider\n.idea/\n*.sln.iml\n\n# CodeRush\n.cr/\n\n# Python Tools for Visual Studio (PTVS)\n__pycache__/\n*.pyc\nNK2Tray.exe.Config\nSam's\\ Releases/\n"
  },
  {
    "path": "NK2Tray/App.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<configuration>\n    <startup> \n        <supportedRuntime version=\"v4.0\" sku=\".NETFramework,Version=v4.6.1\" />\n    </startup>\n</configuration>"
  },
  {
    "path": "NK2Tray/AudioDevice.cs",
    "content": "﻿using NAudio.CoreAudioApi;\nusing NAudio.CoreAudioApi.Interfaces;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\n\nnamespace NK2Tray\n{\n    public class AudioDevice\n    {\n        public MidiDevice midiDevice;\n        public MMDeviceCollection outputDevices;\n        public MMDeviceCollection inputDevices;\n\n\n        private List<MixerSession> mixerSessionListCache;\n        private long currentCacheDate;\n        private int cacheExpireTime = 1500;\n\n        private void UpdateDevices()\n        {\n            // Add audio devices to each fader menu items\n            var deviceEnumerator = new MMDeviceEnumerator();\n\n            //device = deviceEnumerator.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);\n            //device.AudioSessionManager.OnSessionCreated += OnSessionCreated;\n            //deviceVolume = device.AudioEndpointVolume;\n\n            outputDevices = deviceEnumerator.EnumerateAudioEndPoints(DataFlow.Render, DeviceState.Active);\n            inputDevices = deviceEnumerator.EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.Active);\n            \n            foreach (MMDevice mmDevice in outputDevices)\n            {\n                mmDevice.AudioSessionManager.OnSessionCreated += OnSessionCreated;\n            }\n\n            foreach (MMDevice mmDevice in inputDevices)\n            {\n                mmDevice.AudioSessionManager.OnSessionCreated += OnSessionCreated;\n            }\n        }\n\n        public AudioEndpointVolume GetDeviceVolumeObject(String deviceIdentifier)\n        {\n            // Used to handle \"COM object that has been separated from its underlying RCW cannot be used\" issue.\n            UpdateDevices();\n            return GetDeviceByIdentifier(deviceIdentifier).AudioEndpointVolume;\n        }\n\n        private void OnSessionCreated(object sender, IAudioSessionControl newSession)\n        {\n            Console.WriteLine(\"OnSessionCreated\");        \n            midiDevice.LoadAssignments();\n\n            // These correspond with the below events handlers\n            //NAudioEventCallbacks callbacks = new NAudioEventCallbacks();\n            //AudioSessionEventsCallback notifications = new AudioSessionEventsCallback(callbacks);\n            //audioSession.RegisterEventClient(callbacks);\n        }\n\n\n\n        /*\n        // Saving these for later because I'll definitely need them.\n        public class NAudioEventCallbacks : IAudioSessionEventsHandler\n        {\n            public void OnChannelVolumeChanged(uint channelCount, IntPtr newVolumes, uint channelIndex) { Console.WriteLine(\"OnChannelVolumeChanged\"); }\n\n            public void OnDisplayNameChanged(string displayName) { Console.WriteLine(\"OnDisplayNameChanged\"); }\n\n            public void OnGroupingParamChanged(ref Guid groupingId) { Console.WriteLine(\"OnGroupingParamChanged\"); }\n\n            public void OnIconPathChanged(string iconPath) { Console.WriteLine(\"OnIconPathChanged\"); }\n\n            public void OnSessionDisconnected(AudioSessionDisconnectReason disconnectReason) { Console.WriteLine(\"OnSessionDisconnected\"); }\n\n            public void OnStateChanged(AudioSessionState state) { Console.WriteLine(\"OnStateChanged\"); }\n\n            public void OnVolumeChanged(float volume, bool isMuted) { Console.WriteLine(\"OnVolumeChanged\"); }\n        }\n        */\n\n        public List<MixerSession> GetCachedMixerSessions()\n        {\n            if (mixerSessionListCache != null && (currentCacheDate + cacheExpireTime > DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond))\n            {\n                return mixerSessionListCache;\n            }\n\n            mixerSessionListCache = GetMixerSessions();\n            currentCacheDate = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;\n            return mixerSessionListCache;\n        }\n\n        private List<MixerSession> GetMixerSessions()\n        {\n            var mixerSessions = new List<MixerSession>();\n            var sessionsByIdent = new Dictionary<String, List<AudioSessionControl>>();\n\n            UpdateDevices();\n            for (int j = 0; j < outputDevices.Count; j++)\n            {\n                var sessions = outputDevices[j].AudioSessionManager.Sessions;\n\n                for (int i = 0; i < sessions.Count; i++)\n                {\n                    var session = sessions[i];\n                    if (session.State != AudioSessionState.AudioSessionStateExpired)\n                    {\n                        String searchIdentifier = session.GetSessionIdentifier.Substring(session.GetSessionIdentifier.IndexOf(\"|\") + 1, session.GetSessionIdentifier.Length - session.GetSessionIdentifier.IndexOf(\"|\") - 1);\n                        if (!sessionsByIdent.ContainsKey(searchIdentifier))\n                            sessionsByIdent[searchIdentifier] = new List<AudioSessionControl>();\n\n                        sessionsByIdent[searchIdentifier].Add(session);\n                    }\n                }\n            }\n\n            /*\n            // Commented out Iput device code because it breaks the session lists when input and ouput is controlled at the same time\n            for (int j = 0; j < inputDevices.Count; j++)\n            {\n                var sessions = inputDevices[j].AudioSessionManager.Sessions;\n                for (int i = 0; i < sessions.Count; i++)\n                {\n                    var session = sessions[i];\n                    if (session.State != AudioSessionState.AudioSessionStateExpired)\n                    {\n                        String searchIdentifier = session.GetSessionIdentifier.Substring(session.GetSessionIdentifier.IndexOf(\"|\") + 1, session.GetSessionIdentifier.Length - session.GetSessionIdentifier.IndexOf(\"|\") - 1);\n                        if (!sessionsByIdent.ContainsKey(searchIdentifier))\n                            sessionsByIdent[searchIdentifier] = new List<AudioSessionControl>();\n\n                        sessionsByIdent[searchIdentifier].Add(session);\n                    }\n                }\n            }\n            */\n\n            foreach (var ident in sessionsByIdent.Keys.ToList())\n            {\n                var identSessions = sessionsByIdent[ident]; //.OrderBy(i => (int)Process.GetProcessById((int)i.GetProcessID).MainWindowHandle).ToList();\n\n                bool dup = identSessions.Count > 1;\n\n                var process = FindLivingProcess(identSessions);\n                string label = (process != null) ? process.ProcessName : ident;\n\n                if (HasSystemSoundsSession(identSessions))\n                    label = \"System Sounds\";\n                                \n                var mixerSession = new MixerSession(this, label, ident, identSessions, SessionType.Application);\n                mixerSessions.Add(mixerSession);\n            }\n\n            return mixerSessions;\n        }\n                \n        public MMDevice GetDeviceByIdentifier(String identifier)\n        {\n            UpdateDevices();\n\n            String deviceId = (identifier==null?\"\":identifier);\n            if (deviceId.IndexOf(\"|\")>-1) { //work with session identifier also\n                deviceId = deviceId.Substring(0, deviceId.IndexOf(\"|\"));\n            };\n\n            for (int i = 0; i < outputDevices.Count; i++)\n            {\n                if (outputDevices[i].ID.Equals(deviceId))\n                    return outputDevices[i];\n            }\n            for (int i = 0; i < inputDevices.Count; i++)\n            {\n                if (inputDevices[i].ID.Equals(deviceId))\n                    return inputDevices[i];\n            }\n            //return default if none found (config/save retro-compatibility)\n            var deviceEnumerator = new MMDeviceEnumerator();\n            return deviceEnumerator.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);\n        }\n\n        public Process FindLivingProcess(List<AudioSessionControl> sessions)\n        {\n            Process process = null;\n            foreach (var session in sessions)\n            {\n                try\n                {\n                    process = Process.GetProcessById((int)session.GetProcessID);\n                    return process;\n                }\n                catch (ArgumentException e)\n                {\n                    Console.WriteLine($@\"Failed to find process {session.GetProcessID}\");\n                }\n            }\n            return process;\n        }\n\n        public bool HasSystemSoundsSession(List<AudioSessionControl> sessions)\n        {\n            foreach (var session in sessions)\n                if (session.IsSystemSoundsSession)\n                    return true;\n\n            return false;\n        }\n\n        public MixerSession FindMixerSession(string sessionIdentifier)\n        {\n            var mixerSessions = GetCachedMixerSessions();\n\n            foreach (var mixerSession in mixerSessions)\n            {\n                foreach (var session in mixerSession.audioSessions)\n                {\n                    if (session.GetSessionIdentifier.Contains(sessionIdentifier)) \n                        return mixerSession;                  \n                }\n            }\n\n            return null;\n        }\n\n        private struct ProcessCache\n        {\n            public Process process;\n            public int id;\n\n            public ProcessCache(Process process, int id)\n            {\n                this.process = process;\n                this.id = id;\n            }\n        }\n        private ProcessCache processCache = new ProcessCache(null, -1);\n              \n        public MixerSession FindMixerSession(int pid)\n        {\n            var mixerSessions = GetCachedMixerSessions();\n\n            foreach (var mixerSession in mixerSessions)\n                foreach (var session in mixerSession.audioSessions)\n                    if (session.GetProcessID == pid)\n                        return mixerSession;\n\n            // if mixer session was not found becuase the pid does not match the pid of any audio session try finding it by process name\n            // this is necessary since chrome and some other applications have some weired process structure\n            if (processCache.id != pid)\n            {\n                processCache = new ProcessCache(Process.GetProcessById(pid), pid);\n            }\n            Process process = processCache.process;\n\n            foreach (var mixerSession in mixerSessions)\n            {\n                if (mixerSession.label.Equals(process.ProcessName))\n                {\n                    return mixerSession;\n                }\n            }\n\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "NK2Tray/Button.cs",
    "content": "﻿using NAudio.Midi;\nusing System;\n\nnamespace NK2Tray\n{\n    public enum ButtonType\n    {\n        MediaPlay,\n        MediaStop,\n        MediaPrevious,\n        MediaNext,\n        MediaRecord\n    }\n\n    public class Button\n    {\n        private bool activeHandling = false;\n\n        private bool light = false;\n\n        public ButtonType buttonType;\n        public int controller;\n        public MidiCommandCode commandCode;\n        public int channel;\n        public MidiOut midiOut;\n\n        public Button(ref MidiOut midiOutRef, ButtonType butType, int cont, bool initialState, MidiCommandCode code=MidiCommandCode.ControlChange)\n        {\n            commandCode = code;\n            channel = 1;\n            buttonType = butType;\n            controller = cont;\n            midiOut = midiOutRef;\n            SetLight(initialState);\n        }\n\n        public void SetLight(bool state)\n        {\n            light = state;\n            if (commandCode == MidiCommandCode.ControlChange)\n                midiOut.Send(new ControlChangeEvent(0, channel, (MidiController)(controller), state ? 127 : 0).GetAsShortMessage());\n            else if (commandCode == MidiCommandCode.NoteOn)\n                midiOut.Send(new NoteOnEvent(0, 1, controller, state ? 127 : 0, 0).GetAsShortMessage());\n        }\n\n        public bool HandleEvent(MidiInMessageEventArgs e, MidiDevice device)\n        {\n            if (!IsHandling())\n            {\n                SetHandling(true);\n\n                if (e.MidiEvent.CommandCode != commandCode)\n                    return false;\n\n                int c;\n\n                if (commandCode == MidiCommandCode.ControlChange)\n                {\n                    var me = (ControlChangeEvent)e.MidiEvent;\n\n                    if (me.Channel != channel || me.ControllerValue != 127) // Only on correct channel and button-down (127)\n                        return false;\n\n                    c = (int)me.Controller;\n                }\n                else if (commandCode == MidiCommandCode.NoteOn)\n                {\n                    var me = (NoteEvent)e.MidiEvent;\n\n                    if (me.Channel != channel || me.Velocity != 127) // Only on correct channel and button-down (127)\n                        return false;\n\n                    c = me.NoteNumber;\n                }\n                else\n                    return false;\n\n                if (c == controller)\n                {\n                    switch (buttonType)\n                    {\n                        case ButtonType.MediaNext:\n                            MediaTools.Next();\n                            break;\n                        case ButtonType.MediaPrevious:\n                            MediaTools.Previous();\n                            break;\n                        case ButtonType.MediaStop:\n                            MediaTools.Stop();\n                            break;\n                        case ButtonType.MediaPlay:\n                            MediaTools.Play();\n                            break;\n                        case ButtonType.MediaRecord:\n                            device.LightShow();\n                            break;\n                        default:\n                            break;\n                    }\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        public bool IsHandling()\n        {\n            return activeHandling;\n        }\n\n        public void SetHandling(bool handling)\n        {\n            activeHandling = handling;\n        }\n\n        public bool GetLight() { return light; }\n\n    }\n}\n"
  },
  {
    "path": "NK2Tray/ConfigSaver.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing System.Configuration;\n\n\nnamespace NK2Tray\n{\n    class ConfigSaver\n    {\n        public static void AddOrUpdateAppSettings(string key, string value)\n        {\n            try\n            {\n                var configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);\n                var settings = configFile.AppSettings.Settings;\n                if (settings[key] == null)\n                {\n                    settings.Add(key, value);\n                }\n                else\n                {\n                    settings[key].Value = value;\n                }\n                configFile.Save(ConfigurationSaveMode.Modified);\n                ConfigurationManager.RefreshSection(configFile.AppSettings.SectionInformation.Name);\n            }\n            catch (ConfigurationErrorsException)\n            {\n                Console.WriteLine(\"Error writing app settings\");\n            }\n        }\n\n        public static string GetAppSettings(string key)\n        {\n            try\n            {\n                var configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);\n                var settings = configFile.AppSettings.Settings;\n                if (settings[key] != null)\n                    return settings[key].Value;\n                else\n                    return null;\n            }\n            catch\n            {\n                Console.WriteLine(\"Error getting app settings\");\n            }\n            return null;\n        }\n    }\n\n}\n"
  },
  {
    "path": "NK2Tray/DevicePathMapper.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace NK2Tray\n{\n    public static class DevicePathMapper\n    {\n        [DllImport(\"Kernel32.dll\", CharSet = CharSet.Unicode)]\n        private static extern uint QueryDosDevice([In] string lpDeviceName, [Out] StringBuilder lpTargetPath, [In] int ucchMax);\n\n        public static string FromDevicePath(string devicePath)\n        {\n            var drive = Array.Find(DriveInfo.GetDrives(), d => devicePath.StartsWith(d.GetDevicePath(), StringComparison.InvariantCultureIgnoreCase));\n            return drive != null ?\n                devicePath.ReplaceFirst(drive.GetDevicePath(), drive.GetDriveLetter()) :\n                null;\n        }\n\n        private static string GetDevicePath(this DriveInfo driveInfo)\n        {\n            var devicePathBuilder = new StringBuilder(128);\n            return QueryDosDevice(driveInfo.GetDriveLetter(), devicePathBuilder, devicePathBuilder.Capacity + 1) != 0 ?\n                devicePathBuilder.ToString() :\n                null;\n        }\n\n        private static string GetDriveLetter(this DriveInfo driveInfo)\n        {\n            return driveInfo.Name.Substring(0, 2);\n        }\n\n        private static string ReplaceFirst(this string text, string search, string replace)\n        {\n            int pos = text.IndexOf(search);\n            if (pos < 0)\n            {\n                return text;\n            }\n            return text.Substring(0, pos) + replace + text.Substring(pos + search.Length);\n        }\n    }\n}\n"
  },
  {
    "path": "NK2Tray/EasyControl.cs",
    "content": "﻿using NAudio.Midi;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace NK2Tray\n{\n    public class EasyControl : MidiDevice\n    {\n        public override string SearchString => \"easy\";\n        public FaderDef FirstFourFaderDef => new FaderDef(\n            false, // delta\n            127f,   // range\n            1,     // channel\n            false,  // selectPresent\n            true,  // mutePresent\n            false,  // recordPresent\n            false, // subfaderPresent\n            14,     // faderOffset\n            0,    // selectOffset\n            23,    // muteOffset\n            0,    // recordOffset\n            0,    // subFaderOffset\n            MidiCommandCode.ControlChange, // faderCode\n            MidiCommandCode.ControlChange, // selectCode\n            MidiCommandCode.ControlChange, // muteCode\n            MidiCommandCode.ControlChange, // recordCode\n            MidiCommandCode.ControlChange  // subFaderCode\n        );\n\n        public FaderDef SecondFiveFaderDef => new FaderDef(\n            false, // delta\n            127f,   // range\n            1,     // channel\n            false,  // selectPresent\n            true,  // mutePresent\n            false,  // recordPresent\n            false,  // subfaderPresent\n            14,     // faderOffset\n            0,    // selectOffset\n            24,    // muteOffset\n            0,    // recordOffset\n            0,    // subfaderOffset\n            MidiCommandCode.ControlChange, // faderCode\n            MidiCommandCode.ControlChange, // selectCode\n            MidiCommandCode.ControlChange, // muteCode\n            MidiCommandCode.ControlChange, // recordCode\n            MidiCommandCode.ControlChange  // subFaderCode\n        );\n\n        public FaderDef KnobFaderDef => new FaderDef(\n            false, // delta\n            127f,   // range\n            1,     // channel\n            true,  // selectPresent\n            true,  // mutePresent\n            false,  // recordPresent\n            false,  // subfaderPresent\n            1,     // faderOffset\n            55,    // selectOffset\n            58,    // muteOffset\n            0,    // recordOffset\n            0,    // subfaderOffset\n            MidiCommandCode.ControlChange, // faderCode\n            MidiCommandCode.ControlChange, // selectCode\n            MidiCommandCode.ControlChange, // muteCode\n            MidiCommandCode.ControlChange, // recordCode\n            MidiCommandCode.ControlChange  // subFaderCode\n        );\n\n        public FaderDef HorizontalFaderDef => new FaderDef(\n            false, // delta\n            127f,   // range\n            1,     // channel\n            true,  // selectPresent\n            true,  // mutePresent\n            true,  // recordPresent\n            false, // subfaderPresent\n            -1,     // faderOffset\n            -8,    // selectOffset\n            -9,    // muteOffset\n            17,    // recordOffset\n            0,     // subfaderOffset\n            MidiCommandCode.ControlChange, // faderCode\n            MidiCommandCode.ControlChange, // selectCode\n            MidiCommandCode.ControlChange, // muteCode\n            MidiCommandCode.ControlChange, // recordCode\n            MidiCommandCode.ControlChange  // subFaderCode\n        );\n\n        public EasyControl(AudioDevice audioDev)\n        {\n            audioDevices = audioDev;\n            FindMidiIn();\n            FindMidiOut();\n\n            if (Found)\n            {\n                ResetAllLights();\n                InitFaders();\n                InitButtons();\n                LoadAssignments();\n                ListenForMidi();\n            }\n        }\n\n        public override void ResetAllLights()\n        {\n            foreach (var i in Enumerable.Range(0, 128))\n                midiOut.Send(new ControlChangeEvent(0, 1, (MidiController)i, 0).GetAsShortMessage());\n        }\n\n        public override void SetLight(int controller, bool state)\n        {\n            midiOut.Send(new ControlChangeEvent(0, 1, (MidiController)(controller), state ? 127 : 0).GetAsShortMessage());\n        }\n\n        public override void InitFaders()\n        {\n            faders = new List<Fader>();\n\n            foreach (var i in Enumerable.Range(0, 11))\n            {\n                Fader fader = new Fader(this, i, SelectFaderDef(i));\n                fader.ResetLights();\n                faders.Add(fader);\n            }\n        }\n\n        public FaderDef SelectFaderDef(int faderNum)\n        {\n            if (faderNum < 4) return FirstFourFaderDef;\n            if (faderNum < 9) return SecondFiveFaderDef;\n            if (faderNum == 9) return KnobFaderDef;\n\n            return HorizontalFaderDef;\n        }\n\n        public override void InitButtons()\n        {\n            buttons = new List<Button>();\n            buttons.Add(new Button(ref midiOut,  ButtonType.MediaPrevious, 34, true));\n            buttons.Add(new Button(ref midiOut,  ButtonType.MediaNext,     35, true));\n            buttons.Add(new Button(ref midiOut,  ButtonType.MediaStop,     36, false));\n            buttons.Add(new Button(ref midiOut,  ButtonType.MediaPlay,     37, true));\n            buttons.Add(new Button(ref midiOut,  ButtonType.MediaRecord,   38, false));\n        }\n    }\n}\n"
  },
  {
    "path": "NK2Tray/Fader.cs",
    "content": "﻿using NAudio.Midi;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace NK2Tray\n{\n    public class FaderDef\n    {\n        public bool delta;\n        public float faderRange;\n        public int channel;\n        public bool selectPresent;\n        public bool mutePresent;\n        public bool recordPresent;\n        public bool subFaderPresent;\n        public int faderOffset;\n        public int selectOffset;\n        public int muteOffset;\n        public int recordOffset;\n        public int subFaderOffset;\n        public MidiCommandCode faderCode;\n        public MidiCommandCode selectCode;\n        public MidiCommandCode muteCode;\n        public MidiCommandCode recordCode;\n        public MidiCommandCode subFaderCode;\n        public int faderChannelOverride;\n        public int selectChannelOverride;\n        public int muteChannelOverride;\n        public int recordChannelOverride;\n        public int subFaderChannelOverride;\n\n        public FaderDef(\n            bool _delta, float _faderRange, int _channel,\n            bool _selectPresent, bool _mutePresent, bool _recordPresent, bool _subFaderPresent,\n            int _faderOffset, int _selectOffset, int _muteOffset, int _recordOffset, int _subFaderOffset,\n            MidiCommandCode _faderCode, MidiCommandCode _selectCode, MidiCommandCode _muteCode, MidiCommandCode _recordCode, MidiCommandCode _subFaderCode,\n            int _faderChannelOverride = -1, int _selectChannelOverride = -1, int _muteChannelOverride = -1, int _recordChannelOverride = -1, int _subFaderChannelOverride = -1)\n        {\n            delta = _delta;\n            faderRange = _faderRange;\n            channel = _channel;\n            selectPresent = _selectPresent;\n            mutePresent = _mutePresent;\n            recordPresent = _recordPresent;\n            subFaderPresent = _subFaderPresent;\n            faderOffset = _faderOffset;\n            selectOffset = _selectOffset;\n            muteOffset = _muteOffset;\n            recordOffset = _recordOffset;\n            subFaderOffset = _subFaderOffset;\n            faderCode = _faderCode;\n            selectCode = _selectCode;\n            muteCode = _muteCode;\n            recordCode = _recordCode;\n            subFaderCode = _subFaderCode;\n            faderChannelOverride = _faderChannelOverride;\n            selectChannelOverride = _selectChannelOverride;\n            muteChannelOverride = _muteChannelOverride;\n            recordChannelOverride = _recordChannelOverride;\n            subFaderChannelOverride = _subFaderChannelOverride;\n        }\n    }\n\n    public class Fader\n    {\n        private bool activeHandling = false;\n\n        private bool selectLight = false;\n        private bool muteLight = false;\n        private bool recordLight = false;\n\n        public int faderNumber;\n        public FaderDef faderDef;\n        public MixerSession assignment;\n        public bool assigned;\n        public MidiOut midiOut;\n        public MidiDevice parent;\n        public string identifier;\n        public string applicationPath;\n        public string applicationName;\n\n        public float[] steps;\n        public float pow;\n        public float faderPositionMultiplier;\n        private int primaryFaderHardwareValue;\n\n        public Fader(MidiDevice midiDevice, int faderNum)\n        {\n            parent = midiDevice;\n            midiOut = midiDevice.midiOut;\n            faderNumber = faderNum;\n            faderDef = parent.DefaultFaderDef;\n            SetCurve(1f);\n        }\n\n        public Fader(MidiDevice midiDevice, int faderNum, FaderDef _faderDef)\n        {\n            parent = midiDevice;\n            midiOut = midiDevice.midiOut;\n            faderNumber = faderNum;\n            faderDef = _faderDef;\n            SetCurve(1f);\n        }\n\n        public void SetCurve(float _pow)\n        {\n            pow = _pow;\n            steps = calculateSteps();\n            parent.SetVolumeIndicator(faderNumber, assignment != null ? assignment.GetVolume() : -1);\n        }\n\n        private float[] calculateSteps()\n        {\n            if (!faderDef.delta) return new float[0];\n\n            return Enumerable.Range(0, (int)faderDef.faderRange + 1).Select(stage => getVolumeFromHardwarePositionUsingMultiplier(stage)).ToArray();\n        }\n\n        public float getVolumeFromHardwarePositionUsingMultiplier(float position)\n        {\n            var virtualPosition = position * faderPositionMultiplier;\n            return (float)Math.Pow(virtualPosition / faderDef.faderRange, pow);\n        }\n\n        public float getVolFromStage(int stage)\n        {\n            return (float)Math.Pow((double)stage / faderDef.faderRange, pow);\n        }\n\n        private int inputController => faderNumber + faderDef.faderOffset;\n        private int selectController => faderNumber + faderDef.selectOffset;\n        private int muteController => faderNumber + faderDef.muteOffset;\n        private int recordController => faderNumber + faderDef.recordOffset;\n\n        public void ResetLights()\n        {\n            SetSelectLight(false);\n            SetMuteLight(false);\n            SetRecordLight(false);\n        }\n\n        public void Assign(MixerSession mixerSession)\n        {\n            assigned = true;\n            assignment = mixerSession;\n            identifier = mixerSession.sessionIdentifier;\n            convertToApplicationPath(identifier);\n            applicationName = mixerSession.label;\n            SetSelectLight(true);\n            SetRecordLight(false);\n            SetMuteLight(mixerSession.GetMute());\n\n            if (faderDef.delta)\n                parent.SetVolumeIndicator(faderNumber, mixerSession.GetVolume());\n        }\n\n        public void AssignInactive(string ident)\n        {\n            identifier = ident;\n            convertToApplicationPath(identifier);\n            assigned = false;\n            SetSelectLight(true);\n            SetRecordLight(true);\n            SetMuteLight(false);\n        }\n\n        public void Unassign()\n        {\n            assigned = false;\n            assignment = null;\n            SetSelectLight(false);\n            SetRecordLight(false);\n            SetMuteLight(false);\n            identifier = \"\";\n            if (faderDef.delta)\n                parent.SetVolumeIndicator(faderNumber, -1);\n        }\n\n        private void convertToApplicationPath(string ident)\n        {\n            if (\n                ident != null\n                && ident != \"\"\n                && !ident.StartsWith(\"#\")\n                && !ident.Substring(0, Math.Min(10, ident.Length)).Equals(\"__MASTER__\")\n                && ident != \"__FOCUS__\"\n            ) // TODO cleaner handling of special fader types\n            {\n                //\"{0.0.0.00000000}.{...}|\\\\Device\\\\HarddiskVolume8\\\\Users\\\\Dr. Locke\\\\AppData\\\\Roaming\\\\Spotify\\\\Spotify.exe%b{00000000-0000-0000-0000-000000000000}\"\n                int deviceIndex = ident.IndexOf(\"\\\\Device\");\n                int endIndex = ident.IndexOf(\"%b{\");\n                ident = ident.Substring(deviceIndex, endIndex - deviceIndex);\n                applicationPath = DevicePathMapper.FromDevicePath(ident);\n            }\n        }\n\n        public void SetSelectLight(bool state)\n        {\n            selectLight = state;\n            parent.SetLight(selectController, state);\n        }\n\n        public void SetMuteLight(bool state)\n        {\n            muteLight = state;\n            parent.SetLight(muteController, state);\n        }\n\n        public void SetRecordLight(bool state)\n        {\n            recordLight = state;\n            parent.SetLight(recordController, state);\n        }\n\n        public bool GetSelectLight() { return selectLight; }\n\n        public bool GetMuteLight() { return muteLight; }\n\n        public bool GetRecordLight() { return recordLight; }\n\n        public bool Match(int faderNumber, MidiEvent midiEvent, MidiCommandCode code, int offset, int channel = -1)\n        {\n            if (channel < 0)\n                channel = faderDef.channel;\n            if (midiEvent.Channel != channel)\n                return false;\n            if (midiEvent.CommandCode != code)\n                return false;\n            if (code == MidiCommandCode.ControlChange)\n            {\n                var me = (ControlChangeEvent)midiEvent;\n                if ((int)me.Controller == faderNumber + offset)\n                    return true;\n            }\n            else if (code == MidiCommandCode.NoteOn)\n            {\n                var me = (NoteEvent)midiEvent;\n                if (me.NoteNumber == faderNumber + offset)\n                    return true;\n            }\n            else if (code == MidiCommandCode.PitchWheelChange)\n            {\n                return true;\n            }\n\n            return false;\n        }\n\n        public int GetValue(MidiEvent midiEvent)\n        {\n            if (midiEvent.CommandCode == MidiCommandCode.ControlChange)\n            {\n                var me = (ControlChangeEvent)midiEvent;\n                return me.ControllerValue;\n            }\n            else if (midiEvent.CommandCode == MidiCommandCode.NoteOn)\n            {\n                var me = (NoteEvent)midiEvent;\n                return me.Velocity;\n            }\n            else if (midiEvent.CommandCode == MidiCommandCode.PitchWheelChange)\n            {\n                var me = (PitchWheelChangeEvent)midiEvent;\n                return me.Pitch;\n            }\n\n            return 0;\n        }\n\n        public List<Fader> GetMatchingFaders()\n        {\n            MixerSession focusMixerSession = null;\n\n            bool haveFocusSlider = parent.faders.Any(fader => (\n                fader.assignment != null\n                && fader.assignment.sessionType == SessionType.Focus\n            ));\n\n            if (haveFocusSlider)\n            {\n                int pid = WindowTools.GetForegroundPID();\n                focusMixerSession = assignment.devices.FindMixerSession(pid);\n            }\n\n            if (assignment == null)\n                return parent.faders.FindAll(fader => fader.assignment == null);\n\n            if (assignment.sessionType == SessionType.Master)\n            {\n                return parent.faders.FindAll(fader =>\n                {\n                    if (fader == this) return true;\n                    if (fader.assignment == null) return false;\n                    if (fader.assignment.sessionType != SessionType.Master) return false;\n\n                    return fader.assignment.parentDeviceIdentifier == assignment.parentDeviceIdentifier;\n                });\n            }\n\n            if (assignment.sessionType == SessionType.Focus)\n            {\n                return parent.faders.FindAll(fader =>\n                {\n                    if (fader == this) return true;\n                    if (fader.assignment == null) return false;\n                    if (fader.assignment.sessionType == SessionType.Focus) return true;\n\n                    return fader.assignment.HasCrossoverProcesses(focusMixerSession);\n                });\n            }\n\n            if (assignment.sessionType == SessionType.Application)\n            {\n                return parent.faders.FindAll(fader =>\n                {\n                    if (fader == this) return true;\n                    if (fader.assignment == null) return false;\n\n                    if (fader.assignment.sessionType == SessionType.Application)\n                        return fader.assignment.HasCrossoverProcesses(assignment);\n\n                    if (fader.assignment.sessionType == SessionType.Focus)\n                        return assignment.HasCrossoverProcesses(focusMixerSession);\n\n                    return false;\n                });\n            }\n\n            if (assignment.sessionType == SessionType.SystemSounds)\n            {\n                return parent.faders.FindAll(fader => (\n                    fader.assignment != null\n                    && fader.assignment.sessionType == SessionType.SystemSounds\n                ));\n            }\n\n            return new List<Fader>();\n        }\n\n        public bool HandleEvent(MidiInMessageEventArgs e)\n        {\n            if (!IsHandling())\n            {\n                SetHandling(true);\n\n                //if loaded inactive, search again\n                if (!assigned && identifier != null && !identifier.Equals(\"\"))\n                {\n                    assignment = parent.audioDevices.FindMixerSession(identifier);\n                    if (assignment != null)\n                    {\n                        assigned = true;\n                    }\n                }\n\n                // Fader match\n                if (assigned && Match(faderNumber, e.MidiEvent, faderDef.faderCode, faderDef.faderOffset, faderDef.faderChannelOverride))\n                {\n\n                    var hardwareValue = GetValue(e.MidiEvent);\n                    primaryFaderHardwareValue = hardwareValue;\n                    return SetVolume(hardwareValue);\n                }\n\n                // SubFader Match\n                if (\n                    faderDef.subFaderPresent\n                    && assigned\n                    && Match(faderNumber, e.MidiEvent, faderDef.subFaderCode, faderDef.subFaderOffset, faderDef.subFaderChannelOverride))\n                {\n\n                    this.faderPositionMultiplier = GetValue(e.MidiEvent) / faderDef.faderRange;\n                    this.steps = calculateSteps();\n\n                    return SetVolume(primaryFaderHardwareValue);\n                }\n\n                // Select match\n                if (\n                    faderDef.selectPresent\n                    && Match(faderNumber, e.MidiEvent, faderDef.selectCode, faderDef.selectOffset, faderDef.selectChannelOverride)\n                )\n                {\n                    if (GetValue(e.MidiEvent) != 127) // Only on button-down\n                        return true;\n\n                    Console.WriteLine($@\"Attempting to assign current window to fader {faderNumber}\");\n                    if (assigned)\n                    {\n                        Unassign();\n                        parent.SaveAssignments();\n                    }\n                    else\n                    {\n                        var pid = WindowTools.GetForegroundPID();\n                        var mixerSession = parent.audioDevices.FindMixerSession(pid);\n                        if (mixerSession != null)\n                        {\n                            Assign(mixerSession);\n                            parent.SaveAssignments();\n                        }\n                        else\n                            Console.WriteLine($@\"MixerSession not found for pid {pid}\");\n                    }\n                    return true;\n                }\n\n                // Mute match\n                if (\n                    faderDef.mutePresent\n                    && assigned\n                    && Match(faderNumber, e.MidiEvent, faderDef.muteCode, faderDef.muteOffset, faderDef.muteChannelOverride)\n                )\n                {\n                    if (GetValue(e.MidiEvent) != 127) // Only on button-down\n                        return true;\n\n                    var muteStatus = assignment.ToggleMute();\n                    SetMuteLight(muteStatus);\n\n                    if (assignment.IsDead())\n                    {\n                        SetRecordLight(true);\n\n                        return true;\n                    }\n\n                    List<Fader> fadersToAffect = GetMatchingFaders();\n                    fadersToAffect.ForEach(fader => fader.SetMuteLight(muteStatus));\n\n                    return true;\n                }\n\n                // Record match\n                if (\n                    faderDef.recordPresent\n                    && assigned\n                    && applicationPath != null\n                    && Match(faderNumber, e.MidiEvent, faderDef.recordCode, faderDef.recordOffset, faderDef.recordChannelOverride)\n                )\n                {\n                    if (GetValue(e.MidiEvent) != 127) // Only on button-down\n                        return true;\n\n                    if (WindowTools.IsProcessByNameRunning(applicationName))\n                        SetRecordLight(false);\n                    else\n                    {\n                        WindowTools.StartApplication(applicationPath);\n                    }\n\n                    return true;\n                }\n            }\n            return false;\n\n        }\n\n        /// <summary>\n        /// This method sets the volume of the assigned ( if any ) application.\n        /// It utilises the \"hardwarePosition\" passed as a parameter but in sub calls it will\n        /// augment that value with the value of \"faderPositionMultiplier\" which is set elsewhere\n        /// </summary>\n        /// <param name=\"hardwarePosition\">Position of the primary fader as reported by the MidiDevice</param>\n        /// <returns></returns>\n        private bool SetVolume(int hardwarePosition)\n        {\n            if (assignment.sessionType == SessionType.Application)\n            {\n                MixerSession\n                    newAssignment =\n                        assignment.devices.FindMixerSession(assignment\n                            .sessionIdentifier); //update list for re-routered app, but only overrides\n                if (newAssignment == null) //if there is new assignments, otherwise, there is no more a inactive\n                {\n                    //MixerSession to hold the label\n                    SetRecordLight(true);\n                    return true;\n                }\n\n                assignment = newAssignment;\n            }\n\n            float newVol;\n\n            if (faderDef.delta)\n            {\n                var val = hardwarePosition;\n                var volNow = assignment.GetVolume();\n                var nearestStep = steps.Select((x, i) => new { Index = i, Distance = Math.Abs(volNow - x) })\n                    .OrderBy(x => x.Distance).First().Index;\n                int nextStepIndex;\n                var volumeGoingDown = val > faderDef.faderRange / 2;\n\n                if (volumeGoingDown)\n                    nextStepIndex = Math.Max(nearestStep - 1, 0);\n                else\n                    nextStepIndex = Math.Min(nearestStep + 1, steps.Length - 1);\n\n                newVol = steps[nextStepIndex];\n                assignment.SetVolume(newVol);\n            }\n            else\n            {\n                newVol = getVolumeFromHardwarePositionUsingMultiplier(hardwarePosition);\n                assignment.SetVolume(newVol);\n            }\n\n            if (assignment.IsDead())\n            {\n                SetRecordLight(true);\n\n                return true;\n            }\n\n            List<Fader> fadersToAffect = GetMatchingFaders();\n            fadersToAffect.ForEach(fader => fader.parent.SetVolumeIndicator(fader.faderNumber, newVol));\n\n            return true;\n        }\n\n        public bool IsHandling()\n        {\n            return activeHandling;\n        }\n\n        public void SetHandling(bool handling)\n        {\n            activeHandling = handling;\n        }\n    }\n}\n"
  },
  {
    "path": "NK2Tray/FodyWeavers.xml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Weavers xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"FodyWeavers.xsd\">\n  <Costura />\n</Weavers>"
  },
  {
    "path": "NK2Tray/FodyWeavers.xsd",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n  <!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->\n  <xs:element name=\"Weavers\">\n    <xs:complexType>\n      <xs:all>\n        <xs:element name=\"Costura\" minOccurs=\"0\" maxOccurs=\"1\">\n          <xs:complexType>\n            <xs:all>\n              <xs:element minOccurs=\"0\" maxOccurs=\"1\" name=\"ExcludeAssemblies\" type=\"xs:string\">\n                <xs:annotation>\n                  <xs:documentation>A list of assembly names to exclude from the default action of \"embed all Copy Local references\", delimited with line breaks</xs:documentation>\n                </xs:annotation>\n              </xs:element>\n              <xs:element minOccurs=\"0\" maxOccurs=\"1\" name=\"IncludeAssemblies\" type=\"xs:string\">\n                <xs:annotation>\n                  <xs:documentation>A list of assembly names to include from the default action of \"embed all Copy Local references\", delimited with line breaks.</xs:documentation>\n                </xs:annotation>\n              </xs:element>\n              <xs:element minOccurs=\"0\" maxOccurs=\"1\" name=\"Unmanaged32Assemblies\" type=\"xs:string\">\n                <xs:annotation>\n                  <xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with line breaks.</xs:documentation>\n                </xs:annotation>\n              </xs:element>\n              <xs:element minOccurs=\"0\" maxOccurs=\"1\" name=\"Unmanaged64Assemblies\" type=\"xs:string\">\n                <xs:annotation>\n                  <xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with line breaks.</xs:documentation>\n                </xs:annotation>\n              </xs:element>\n              <xs:element minOccurs=\"0\" maxOccurs=\"1\" name=\"PreloadOrder\" type=\"xs:string\">\n                <xs:annotation>\n                  <xs:documentation>The order of preloaded assemblies, delimited with line breaks.</xs:documentation>\n                </xs:annotation>\n              </xs:element>\n            </xs:all>\n            <xs:attribute name=\"CreateTemporaryAssemblies\" type=\"xs:boolean\">\n              <xs:annotation>\n                <xs:documentation>This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file.</xs:documentation>\n              </xs:annotation>\n            </xs:attribute>\n            <xs:attribute name=\"IncludeDebugSymbols\" type=\"xs:boolean\">\n              <xs:annotation>\n                <xs:documentation>Controls if .pdbs for reference assemblies are also embedded.</xs:documentation>\n              </xs:annotation>\n            </xs:attribute>\n            <xs:attribute name=\"DisableCompression\" type=\"xs:boolean\">\n              <xs:annotation>\n                <xs:documentation>Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.</xs:documentation>\n              </xs:annotation>\n            </xs:attribute>\n            <xs:attribute name=\"DisableCleanup\" type=\"xs:boolean\">\n              <xs:annotation>\n                <xs:documentation>As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.</xs:documentation>\n              </xs:annotation>\n            </xs:attribute>\n            <xs:attribute name=\"LoadAtModuleInit\" type=\"xs:boolean\">\n              <xs:annotation>\n                <xs:documentation>Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code.</xs:documentation>\n              </xs:annotation>\n            </xs:attribute>\n            <xs:attribute name=\"IgnoreSatelliteAssemblies\" type=\"xs:boolean\">\n              <xs:annotation>\n                <xs:documentation>Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior.</xs:documentation>\n              </xs:annotation>\n            </xs:attribute>\n            <xs:attribute name=\"ExcludeAssemblies\" type=\"xs:string\">\n              <xs:annotation>\n                <xs:documentation>A list of assembly names to exclude from the default action of \"embed all Copy Local references\", delimited with |</xs:documentation>\n              </xs:annotation>\n            </xs:attribute>\n            <xs:attribute name=\"IncludeAssemblies\" type=\"xs:string\">\n              <xs:annotation>\n                <xs:documentation>A list of assembly names to include from the default action of \"embed all Copy Local references\", delimited with |.</xs:documentation>\n              </xs:annotation>\n            </xs:attribute>\n            <xs:attribute name=\"Unmanaged32Assemblies\" type=\"xs:string\">\n              <xs:annotation>\n                <xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with |.</xs:documentation>\n              </xs:annotation>\n            </xs:attribute>\n            <xs:attribute name=\"Unmanaged64Assemblies\" type=\"xs:string\">\n              <xs:annotation>\n                <xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with |.</xs:documentation>\n              </xs:annotation>\n            </xs:attribute>\n            <xs:attribute name=\"PreloadOrder\" type=\"xs:string\">\n              <xs:annotation>\n                <xs:documentation>The order of preloaded assemblies, delimited with |.</xs:documentation>\n              </xs:annotation>\n            </xs:attribute>\n          </xs:complexType>\n        </xs:element>\n      </xs:all>\n      <xs:attribute name=\"VerifyAssembly\" type=\"xs:boolean\">\n        <xs:annotation>\n          <xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>\n        </xs:annotation>\n      </xs:attribute>\n      <xs:attribute name=\"VerifyIgnoreCodes\" type=\"xs:string\">\n        <xs:annotation>\n          <xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>\n        </xs:annotation>\n      </xs:attribute>\n      <xs:attribute name=\"GenerateXsd\" type=\"xs:boolean\">\n        <xs:annotation>\n          <xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>\n        </xs:annotation>\n      </xs:attribute>\n    </xs:complexType>\n  </xs:element>\n</xs:schema>"
  },
  {
    "path": "NK2Tray/IconExtractor.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing System.Runtime.InteropServices;\n\nnamespace NK2Tray\n{\n    public class IconExtractor\n    {\n        public static Icon Extract(string file, int number, bool largeIcon)\n        {\n            IntPtr large;\n            IntPtr small;\n            ExtractIconEx(file, number, out large, out small, 1);\n            try\n            {\n                return Icon.FromHandle(largeIcon ? large : small);\n            }\n            catch\n            {\n                return null;\n            }\n        }\n\n        [DllImport(\"Shell32.dll\")]\n        private static extern int ExtractIconEx(string sFile, int iIndex, out IntPtr piLargeVersion, out IntPtr piSmallVersion, int amountIcons);\n    }\n}\n"
  },
  {
    "path": "NK2Tray/MediaTools.cs",
    "content": "﻿using System;\nusing System.Runtime.InteropServices;\n\nnamespace NK2Tray\n{\n    class MediaTools\n    {\n        [DllImport(\"user32.dll\", SetLastError = true)]\n        public static extern void keybd_event(byte virtualKey, byte scanCode, uint flags, IntPtr extraInfo);\n\n        public const int VK_MEDIA_NEXT_TRACK = 0xB0;\n        public const int VK_MEDIA_PLAY_PAUSE = 0xB3;\n        public const int VK_MEDIA_PREV_TRACK = 0xB1;\n        public const int VK_MEDIA_STOP = 0xB2;\n        public const int KEYEVENTF_EXTENDEDKEY = 0x0001; //Key down flag\n        public const int KEYEVENTF_KEYUP = 0x0002; //Key up flag\n\n        public static void Play()\n        {\n            keybd_event(VK_MEDIA_PLAY_PAUSE, 0, KEYEVENTF_EXTENDEDKEY, IntPtr.Zero);\n            keybd_event(VK_MEDIA_PLAY_PAUSE, 0, KEYEVENTF_KEYUP, IntPtr.Zero);\n        }\n\n        public static void Stop()\n        {\n            keybd_event(VK_MEDIA_STOP, 0, KEYEVENTF_EXTENDEDKEY, IntPtr.Zero);\n            keybd_event(VK_MEDIA_STOP, 0, KEYEVENTF_KEYUP, IntPtr.Zero);\n        }\n\n        public static void Next()\n        {\n            keybd_event(VK_MEDIA_NEXT_TRACK, 0, KEYEVENTF_EXTENDEDKEY, IntPtr.Zero);\n            keybd_event(VK_MEDIA_NEXT_TRACK, 0, KEYEVENTF_KEYUP, IntPtr.Zero);\n        }\n\n        public static void Previous()\n        {\n            keybd_event(VK_MEDIA_PREV_TRACK, 0, KEYEVENTF_EXTENDEDKEY, IntPtr.Zero);\n            keybd_event(VK_MEDIA_PREV_TRACK, 0, KEYEVENTF_KEYUP, IntPtr.Zero);\n        }\n    }\n}\n"
  },
  {
    "path": "NK2Tray/MidiDevice.cs",
    "content": "﻿using NAudio.CoreAudioApi;\nusing NAudio.Midi;\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Configuration;\nusing System.Linq;\n\nnamespace NK2Tray\n{\n    public enum SendEvent\n    {\n        AssignedState,\n        MuteState,\n        ErrorState,\n        MediaPlay,\n        MediaStop,\n        MediaPrevious,\n        MediaNext,\n        MediaRecord\n    }\n\n    public class MidiDevice\n    {\n        public MidiIn midiIn;\n        public MidiOut midiOut;\n\n        public List<Fader> faders;\n        public List<Button> buttons;\n        public Hashtable buttonsMappingTable;\n\n        public AudioDevice audioDevices;\n\n        public virtual string SearchString => \"wobbo\";\n\n        public virtual FaderDef DefaultFaderDef =>\n            new FaderDef(\n                false,\n                1f,\n                1,\n                true,\n                true,\n                true,\n                true,\n                0,\n                0,\n                0,\n                0,\n                0,\n                MidiCommandCode.ControlChange,\n                MidiCommandCode.ControlChange,\n                MidiCommandCode.ControlChange,\n                MidiCommandCode.ControlChange,\n                MidiCommandCode.ControlChange);\n\n        public MidiDevice()\n        {\n            Console.WriteLine($@\"Initializing Midi Device {SearchString}\");\n        }\n\n        public bool Found => (midiIn != null && midiOut != null);\n\n        public void FindMidiIn()\n        {\n            for (int i = 0; i < MidiIn.NumberOfDevices; i++)\n            {\n                Console.WriteLine(\"MIDI IN: \" + MidiIn.DeviceInfo(i).ProductName);\n                if (MidiIn.DeviceInfo(i).ProductName.ToLower().Contains(SearchString))\n                {\n                    midiIn = new MidiIn(i);\n                    Console.WriteLine($@\"Assigning MidiIn: {MidiIn.DeviceInfo(i).ProductName}\");\n                    break;\n                }\n            }\n        }\n\n        public void FindMidiOut()\n        {\n            for (int i = 0; i < MidiOut.NumberOfDevices; i++)\n            {\n                Console.WriteLine(\"MIDI OUT: \" + MidiOut.DeviceInfo(i).ProductName);\n                if (MidiOut.DeviceInfo(i).ProductName.ToLower().Contains(SearchString))\n                {\n                    midiOut = new MidiOut(i);\n                    Console.WriteLine($@\"Assigning MidiOut: {MidiOut.DeviceInfo(i).ProductName}\");\n                    break;\n                }\n            }\n        }\n\n        public void ListenForMidi()\n        {\n            midiIn.MessageReceived += midiIn_MessageReceived;\n            midiIn.ErrorReceived += midiIn_ErrorReceived;\n            midiIn.Start();\n        }\n\n        public void midiIn_ErrorReceived(object sender, MidiInMessageEventArgs e)\n        {\n            Console.WriteLine(String.Format(\"Time {0} Message 0x{1:X8} Event {2}\",\n                e.Timestamp, e.RawMessage, e.MidiEvent));\n        }\n\n        public virtual void midiIn_MessageReceived(object sender, MidiInMessageEventArgs e)\n        {\n            //WindowTools.Dump(e.MidiEvent);\n\n            foreach (var fader in faders)\n            {\n                fader.HandleEvent(e);\n                fader.SetHandling(false);\n            }\n\n            //ControlChangeEvent midiController = null;\n            //\n            //try\n            //{\n            //    midiController = (ControlChangeEvent)e.MidiEvent;\n            //}\n            //catch (System.InvalidCastException exc)\n            //{\n            //    return;\n            //}\n            //\n            //if (midiController == null)\n            //    return;\n            ////key UP...!\n            //if (midiController.ControllerValue == 0)\n            //    return;\n            //\n            //var obj = buttonsMappingTable[(int)midiController.Controller];\n            //if (obj != null)\n            //{\n            //    Button button = (Button)obj;\n            //    button.HandleEvent(e, this);\n            //    button.SetHandling(false);\n            //}\n            //else\n            {\n                foreach (var button in buttons)\n                {\n                    button.HandleEvent(e, this);\n                    button.SetHandling(false);\n                }\n            }\n        }\n\n        public virtual void ResetAllLights() { }\n\n        public virtual void LightShow() { }\n\n        public virtual void SetVolumeIndicator(int fader, float level) { }\n\n        public virtual void SetLight(int controller, bool state) {}\n\n        public virtual void InitFaders()\n        {\n            faders = new List<Fader>();\n        }\n\n        public virtual void InitButtons()\n        {\n            buttons = new List<Button>();\n        }\n\n        public void SetCurve(float pow)\n        {\n            faders.ForEach(fader => fader.SetCurve(pow));\n        }\n\n        public void LoadAssignments()\n        {\n            bool foundAssignments = false;\n\n            foreach (var fader in faders)\n            {\n                Console.WriteLine(\"Getting setting: \" + fader.faderNumber.ToString());\n                var ident = ConfigSaver.GetAppSettings(fader.faderNumber.ToString());\n\n                Console.WriteLine(\"Got setting: \" + ident);\n                if (ident != null)\n                {\n                    if (ident.Equals(\"__FOCUS__\"))\n                    {\n                        foundAssignments = true;\n                        fader.Assign(new MixerSession(\"\", audioDevices, \"Focus\", SessionType.Focus));\n                    }\n                    else if (ident.Equals(\"__MASTER__\") || (ident.Substring(0, Math.Min(10, ident.Length)).Equals(\"__MASTER__\")))\n                    {\n                        foundAssignments = true;\n                        MMDevice mmDevice = audioDevices.GetDeviceByIdentifier(ident.IndexOf(\"|\") >= 0 ? ident.Substring(ident.IndexOf(\"|\")+1) : \"\");\n                        fader.Assign(new MixerSession(mmDevice.ID, audioDevices, \"Master\", SessionType.Master));\n                    }                    \n                    else if (ident.Length > 0)\n                    {\n                        foundAssignments = true;\n                        var matchingSession = audioDevices.FindMixerSession(ident);\n                        if (matchingSession != null)\n                            fader.Assign(matchingSession);\n                        else\n                            fader.AssignInactive(ident);\n                    }\n                    else\n                    {\n                        fader.Unassign();\n                    }\n                }\n\n                var savedSubFaderPosition = ConfigSaver.GetAppSettings(fader.faderNumber.ToString() + \"m\");\n                fader.faderPositionMultiplier = savedSubFaderPosition != null ? float.Parse(savedSubFaderPosition) : 1;\n            }            \n            \n            // Load fader 8 as master volume control as default if no faders are set\n            if (!foundAssignments)\n            {\n                if (faders.Count > 0)\n                {\n                    faders.Last().Assign(new MixerSession(audioDevices.GetDeviceByIdentifier(\"\").ID, audioDevices, \"Master\", SessionType.Master));\n                    SaveAssignments();\n                }\n            }\n            \n        }\n\n        public void SaveAssignments()\n        {\n            Console.WriteLine(\"Saving Assignments\");\n            foreach (var fader in faders)\n            {\n                if (fader.assigned)\n                {\n                    if (fader.assignment.sessionType == SessionType.Master)\n                        ConfigSaver.AddOrUpdateAppSettings(fader.faderNumber.ToString(), \"__MASTER__|\" + fader.assignment.parentDeviceIdentifier );\n                    else if (fader.assignment.sessionType == SessionType.Focus)\n                        ConfigSaver.AddOrUpdateAppSettings(fader.faderNumber.ToString(), \"__FOCUS__\");\n                    else\n                        ConfigSaver.AddOrUpdateAppSettings(fader.faderNumber.ToString(), fader.assignment.sessionIdentifier);\n                }\n                else\n                {\n                    ConfigSaver.AddOrUpdateAppSettings(fader.faderNumber.ToString(), \"\");\n                }\n\n                ConfigSaver.AddOrUpdateAppSettings(fader.faderNumber.ToString() + \"m\", fader.faderPositionMultiplier.ToString());\n            }\n        }\n\n    }\n}\n"
  },
  {
    "path": "NK2Tray/MixerSession.cs",
    "content": "﻿using NAudio.CoreAudioApi;\nusing NAudio.CoreAudioApi.Interfaces;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace NK2Tray\n{\n    public enum SessionType\n    {\n        Application,\n        SystemSounds,\n        Master,\n        Focus\n    }\n\n    /// <summary>\n    /// A <c>MixerSession</c> represents a running application and all audio sessions belonging to it.\n    /// </summary>\n    public class MixerSession\n    {\n        public string label;\n        public string sessionIdentifier;\n        public List<AudioSessionControl> audioSessions;\n        public SessionType sessionType;\n        public AudioDevice devices;\n        public String parentDeviceIdentifier;\n\n        public MixerSession(AudioDevice devices, string labl, string identifier, List<AudioSessionControl> sessions, SessionType sesType)\n        {\n            this.devices = devices;\n   \n            sessionIdentifier = identifier;\n            audioSessions = sessions;\n            sessionType = sesType;\n            label = labl;\n        }\n\n        public MixerSession(String deviceIdentifier, AudioDevice devices, string labl, SessionType sesType)\n        {\n            this.devices = devices;\n            \n            sessionIdentifier = \"\";\n            audioSessions = new List<AudioSessionControl>();\n            sessionType = sesType;\n            parentDeviceIdentifier = deviceIdentifier;\n\n            if (sesType == SessionType.Focus)\n                label = \"Focus\";\n            else\n                label = devices.GetDeviceByIdentifier(deviceIdentifier).FriendlyName + \": \" + labl;\n        }\n\n        public bool IsDead()\n        {\n            bool alive = false;\n            if (sessionType == SessionType.Application)\n            {\n                foreach (var session in audioSessions)\n                    if (session.State != AudioSessionState.AudioSessionStateExpired)\n                        alive = true;\n            }\n            else\n                alive = true;\n\n            return !alive;\n        }\n\n        public void SetVolume(float volume)\n        {\n            if (sessionType == SessionType.Application)\n            {\n                foreach (var session in audioSessions)\n                    session.SimpleAudioVolume.Volume = volume;\n            }\n            else if (sessionType == SessionType.Master)\n            {\n                try\n                {\n                    devices.GetDeviceByIdentifier(parentDeviceIdentifier).AudioEndpointVolume.MasterVolumeLevelScalar = volume;                                   \n                }\n                catch (System.Runtime.InteropServices.InvalidComObjectException e)\n                {\n                    // This catch handles the \"COM object that has been separated from its underlying RCW cannot be used\" issue.\n                    // I believe this happens when we refresh the device when opening the menu, but this is fine for now.\n                    Console.WriteLine($@\"Error when setting master volume: {e.Message}\");\n                    AudioEndpointVolume deviceVolume = devices.GetDeviceByIdentifier(parentDeviceIdentifier).AudioEndpointVolume;\n                    deviceVolume.MasterVolumeLevelScalar = volume;\n                    Console.WriteLine($@\"RETRY: Setting master volume to {volume}\");\n                }\n                catch (System.Runtime.InteropServices.COMException e)\n                {\n                    //TODO find out where this exception comes from and actually fix it\n                    Console.WriteLine(\"COM Execption\" + e);\n                }\n                catch (System.InvalidCastException e)\n                {                    \n                    Console.WriteLine(\"InvalidCastException Exeception\" + e);\n                }\n            } \n            else if (sessionType == SessionType.Focus)\n            {\n                var pid = WindowTools.GetForegroundPID();\n                var mixerSession = devices.FindMixerSession(pid);\n                // Check if null since mixer session might not exist for currently focused window\n                if (mixerSession != null)\n                {\n                    foreach (var session in mixerSession.audioSessions)\n                    {\n                        session.SimpleAudioVolume.Volume = volume;\n                    }\n                }\n            }\n        }\n\n        public float GetVolume()\n        {\n            if (sessionType == SessionType.Application)\n            {\n                foreach (var session in audioSessions)\n                {\n                    var curVol = session.SimpleAudioVolume.Volume;\n                    if (curVol < 0)\n                        curVol = 0;\n                    if (curVol > 1)\n                        curVol = 1;\n                    return curVol;\n                }\n            }\n            else if (sessionType == SessionType.Master)\n            {\n                try\n                {\n                    var curVol = devices.GetDeviceByIdentifier(parentDeviceIdentifier).AudioEndpointVolume.MasterVolumeLevelScalar;\n                    if (curVol < 0)\n                        curVol = 0;\n                    if (curVol > 1)\n                        curVol = 1;\n                    return curVol;\n                }\n                catch (System.Runtime.InteropServices.InvalidComObjectException e)\n                {\n                    // This catch handles the \"COM object that has been separated from its underlying RCW cannot be used\" issue.\n                    // I believe this happens when we refresh the device when opening the menu, but this is fine for now.\n                    Console.WriteLine($@\"Error when getting master volume: {e.Message}\");\n                    var curVol = devices.GetDeviceByIdentifier(parentDeviceIdentifier).AudioEndpointVolume.MasterVolumeLevelScalar;\n                    if (curVol < 0)\n                        curVol = 0;\n                    if (curVol > 1)\n                        curVol = 1;\n                    return curVol;\n                }\n            }\n            else if (sessionType == SessionType.Focus)\n            {\n                var pid = WindowTools.GetForegroundPID();\n                var mixerSession = devices.FindMixerSession(pid);\n                if (mixerSession != null)\n                {\n                    foreach (var session in mixerSession.audioSessions)\n                    {\n                        var curVol = session.SimpleAudioVolume.Volume;\n                        if (curVol < 0)\n                            curVol = 0;\n                        if (curVol > 1)\n                            curVol = 1;\n                        return curVol;\n                    }\n                }\n            }\n            return -1;\n        }\n\n        public float ChangeVolume(float change)\n        {\n            float retVol = -1;\n            if (sessionType == SessionType.Application)\n            {\n                foreach (var session in audioSessions)\n                {\n                    if (retVol < 0)\n                    {\n                        var curVol = session.SimpleAudioVolume.Volume;\n                        curVol += change;\n                        if (curVol < 0)\n                            curVol = 0;\n                        if (curVol > 1)\n                            curVol = 1;\n                        session.SimpleAudioVolume.Volume = curVol;\n                        retVol = curVol;\n                    }\n                    {\n                        session.SimpleAudioVolume.Volume = retVol;\n                    }\n                }\n            }\n            else if (sessionType == SessionType.Master)\n            {\n                try\n                {\n                    var curVol = devices.GetDeviceByIdentifier(parentDeviceIdentifier).AudioEndpointVolume.MasterVolumeLevelScalar;\n                    curVol += change;\n                    if (curVol < 0)\n                        curVol = 0;\n                    if (curVol > 1)\n                        curVol = 1;\n                    devices.GetDeviceByIdentifier(parentDeviceIdentifier).AudioEndpointVolume.MasterVolumeLevelScalar = curVol;\n                    retVol = curVol;\n                }\n                catch (System.Runtime.InteropServices.InvalidComObjectException e)\n                {\n                    // This catch handles the \"COM object that has been separated from its underlying RCW cannot be used\" issue.\n                    // I believe this happens when we refresh the device when opening the menu, but this is fine for now.\n                    Console.WriteLine($@\"Error when setting master volume: {e.Message}\");\n                    AudioEndpointVolume deviceVolume = devices.GetDeviceByIdentifier(parentDeviceIdentifier).AudioEndpointVolume;\n                    var curVol = deviceVolume.MasterVolumeLevelScalar;\n                    curVol += change;\n                    if (curVol < 0)\n                        curVol = 0;\n                    if (curVol > 1)\n                        curVol = 1;\n                    deviceVolume.MasterVolumeLevelScalar = curVol;\n                    Console.WriteLine($@\"RETRY: Setting master volume by {change}\");\n                }\n\n            }\n            else if (sessionType == SessionType.Focus)\n            {\n                var pid = WindowTools.GetForegroundPID();\n                var mixerSession = devices.FindMixerSession(pid);\n                if( mixerSession != null)\n                {\n                    foreach (var session in mixerSession.audioSessions)\n                    {\n                        var curVol = session.SimpleAudioVolume.Volume;\n                        curVol += change;\n                        if (curVol < 0)\n                            curVol = 0;\n                        if (curVol > 1)\n                            curVol = 1;\n                        session.SimpleAudioVolume.Volume = curVol;\n                        retVol = curVol;\n                    }\n                }\n            }\n            return retVol;\n        }\n\n        public bool ToggleMute()\n        {\n            if (sessionType == SessionType.Application)\n            {\n                var muted = !audioSessions.First().SimpleAudioVolume.Mute;\n                foreach (var session in audioSessions)\n                    session.SimpleAudioVolume.Mute = muted;\n                return muted;\n            }\n            else if (sessionType == SessionType.Master)\n            {\n                try\n                {\n                    var muted = !devices.GetDeviceByIdentifier(parentDeviceIdentifier).AudioEndpointVolume.Mute;\n                    devices.GetDeviceByIdentifier(parentDeviceIdentifier).AudioEndpointVolume.Mute = muted;\n                    return muted;\n                }\n                catch (System.Runtime.InteropServices.InvalidComObjectException e)\n                {\n                    // This catch handles the \"COM object that has been separated from its underlying RCW cannot be used\" issue.\n                    // I believe this happens when we refresh the device when opening the menu, but this is fine for now.\n                    Console.WriteLine($@\"Error when toggling mute on master volume: {e.Message}\");\n                    AudioEndpointVolume deviceVolume = devices.GetDeviceByIdentifier(parentDeviceIdentifier).AudioEndpointVolume;\n                    var muted = !deviceVolume.Mute;\n                    deviceVolume.Mute = muted;\n\n                    Console.WriteLine(\"RETRY: toggling mute on master volume\");\n                    return muted;\n                }\n            }\n            else if (sessionType == SessionType.Focus)\n            {\n                var pid = WindowTools.GetForegroundPID();\n                var mixerSession = devices.FindMixerSession(pid);\n                if (mixerSession != null)\n                {\n                    var muted = !mixerSession.audioSessions.First().SimpleAudioVolume.Mute;\n                    foreach (var session in mixerSession.audioSessions)\n                        session.SimpleAudioVolume.Mute = muted;\n                    return muted;\n                }\n            }\n            return false;\n        }\n\n        public bool GetMute()\n        {\n            if (sessionType == SessionType.Master)\n                return devices.GetDeviceByIdentifier(parentDeviceIdentifier).AudioEndpointVolume.Mute;\n\n            var targetAudioSessions = audioSessions;\n\n            if (sessionType == SessionType.Focus)\n            {\n                var pid = WindowTools.GetForegroundPID();\n                var mixerSession = devices.FindMixerSession(pid);\n                if (mixerSession == null) return false;\n                targetAudioSessions = mixerSession.audioSessions;\n            }\n\n            return targetAudioSessions.First().SimpleAudioVolume.Mute;\n        }\n\n        public bool HasCrossoverProcesses(MixerSession other)\n        {\n            if (other == null) return false;\n\n            return audioSessions.Any(session =>\n                other.audioSessions.Any(otherSession =>\n                    session.GetProcessID == otherSession.GetProcessID\n                )\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "NK2Tray/NK2Tray.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <Import Project=\"..\\packages\\Costura.Fody.3.3.0\\build\\Costura.Fody.props\" Condition=\"Exists('..\\packages\\Costura.Fody.3.3.0\\build\\Costura.Fody.props')\" />\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <ProjectGuid>{F88D8F42-CC15-40AE-9301-043313764C4C}</ProjectGuid>\n    <OutputType>WinExe</OutputType>\n    <RootNamespace>NK2Tray</RootNamespace>\n    <AssemblyName>NK2Tray</AssemblyName>\n    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>\n    <FileAlignment>512</FileAlignment>\n    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>\n    <Deterministic>true</Deterministic>\n    <NuGetPackageImportStamp>\n    </NuGetPackageImportStamp>\n    <PublishUrl>publish\\</PublishUrl>\n    <Install>true</Install>\n    <InstallFrom>Disk</InstallFrom>\n    <UpdateEnabled>false</UpdateEnabled>\n    <UpdateMode>Foreground</UpdateMode>\n    <UpdateInterval>7</UpdateInterval>\n    <UpdateIntervalUnits>Days</UpdateIntervalUnits>\n    <UpdatePeriodically>false</UpdatePeriodically>\n    <UpdateRequired>false</UpdateRequired>\n    <MapFileExtensions>true</MapFileExtensions>\n    <ApplicationRevision>0</ApplicationRevision>\n    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>\n    <IsWebBootstrapper>false</IsWebBootstrapper>\n    <UseApplicationTrust>false</UseApplicationTrust>\n    <BootstrapperEnabled>true</BootstrapperEnabled>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\n    <PlatformTarget>AnyCPU</PlatformTarget>\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>full</DebugType>\n    <Optimize>false</Optimize>\n    <OutputPath>bin\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\n    <PlatformTarget>AnyCPU</PlatformTarget>\n    <DebugType>pdbonly</DebugType>\n    <Optimize>true</Optimize>\n    <OutputPath>bin\\Release\\</OutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n  </PropertyGroup>\n  <PropertyGroup>\n    <ApplicationIcon>nk2tray.ico</ApplicationIcon>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"Costura, Version=3.3.0.0, Culture=neutral, PublicKeyToken=9919ef960d84173d, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Costura.Fody.3.3.0\\lib\\net40\\Costura.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"NAudio, Version=1.8.5.0, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\NAudio.1.8.5\\lib\\net35\\NAudio.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.Configuration\" />\n    <Reference Include=\"System.Core\" />\n    <Reference Include=\"System.Xml.Linq\" />\n    <Reference Include=\"System.Data.DataSetExtensions\" />\n    <Reference Include=\"Microsoft.CSharp\" />\n    <Reference Include=\"System.Data\" />\n    <Reference Include=\"System.Deployment\" />\n    <Reference Include=\"System.Drawing\" />\n    <Reference Include=\"System.Net.Http\" />\n    <Reference Include=\"System.Windows.Forms\" />\n    <Reference Include=\"System.Xml\" />\n    <Reference Include=\"WindowsBase\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Include=\"AudioDevice.cs\" />\n    <Compile Include=\"Button.cs\" />\n    <Compile Include=\"ConfigSaver.cs\" />\n    <Compile Include=\"DevicePathMapper.cs\" />\n    <Compile Include=\"EasyControl.cs\" />\n    <Compile Include=\"Fader.cs\" />\n    <Compile Include=\"IconExtractor.cs\" />\n    <Compile Include=\"MediaTools.cs\" />\n    <Compile Include=\"NanoKontrol2.cs\" />\n    <Compile Include=\"MidiDevice.cs\" />\n    <Compile Include=\"MixerSession.cs\" />\n    <Compile Include=\"OP1.cs\" />\n    <Compile Include=\"Program.cs\">\n      <SubType>Form</SubType>\n    </Compile>\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n    <Compile Include=\"WindowTools.cs\" />\n    <Compile Include=\"XtouchMini.cs\" />\n    <EmbeddedResource Include=\"Properties\\Resources.resx\">\n      <Generator>ResXFileCodeGenerator</Generator>\n      <LastGenOutput>Resources.Designer.cs</LastGenOutput>\n      <SubType>Designer</SubType>\n    </EmbeddedResource>\n    <Compile Include=\"Properties\\Resources.Designer.cs\">\n      <AutoGen>True</AutoGen>\n      <DependentUpon>Resources.resx</DependentUpon>\n      <DesignTime>True</DesignTime>\n    </Compile>\n    <None Include=\"packages.config\" />\n    <None Include=\"Properties\\Settings.settings\">\n      <Generator>SettingsSingleFileGenerator</Generator>\n      <LastGenOutput>Settings.Designer.cs</LastGenOutput>\n    </None>\n    <Compile Include=\"Properties\\Settings.Designer.cs\">\n      <AutoGen>True</AutoGen>\n      <DependentUpon>Settings.settings</DependentUpon>\n      <DesignTimeSharedInput>True</DesignTimeSharedInput>\n    </Compile>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"App.config\" />\n  </ItemGroup>\n  <ItemGroup>\n    <EmbeddedResource Include=\"nk2tray.ico\" />\n  </ItemGroup>\n  <ItemGroup>\n    <BootstrapperPackage Include=\".NETFramework,Version=v4.6.1\">\n      <Visible>False</Visible>\n      <ProductName>Microsoft .NET Framework 4.6.1 %28x86 und x64%29</ProductName>\n      <Install>true</Install>\n    </BootstrapperPackage>\n    <BootstrapperPackage Include=\"Microsoft.Net.Framework.3.5.SP1\">\n      <Visible>False</Visible>\n      <ProductName>.NET Framework 3.5 SP1</ProductName>\n      <Install>false</Install>\n    </BootstrapperPackage>\n  </ItemGroup>\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\n  <Import Project=\"..\\packages\\Fody.3.3.5\\build\\Fody.targets\" Condition=\"Exists('..\\packages\\Fody.3.3.5\\build\\Fody.targets')\" />\n  <Target Name=\"EnsureNuGetPackageBuildImports\" BeforeTargets=\"PrepareForBuild\">\n    <PropertyGroup>\n      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>\n    </PropertyGroup>\n    <Error Condition=\"!Exists('..\\packages\\Fody.3.3.5\\build\\Fody.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\Fody.3.3.5\\build\\Fody.targets'))\" />\n    <Error Condition=\"!Exists('..\\packages\\Costura.Fody.3.3.0\\build\\Costura.Fody.props')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\Costura.Fody.3.3.0\\build\\Costura.Fody.props'))\" />\n  </Target>\n</Project>"
  },
  {
    "path": "NK2Tray/NanoKontrol2.cs",
    "content": "﻿using NAudio.Midi;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace NK2Tray\n{\n    public class NanoKontrol2 : MidiDevice\n    {\n        public override string SearchString => \"nano\";\n        public override FaderDef DefaultFaderDef => new FaderDef(\n            false, // delta\n            127f,   // range\n            1,     // channel\n            true,  // selectPresent\n            true,  // mutePresent\n            true,  // recordPresent\n            true,  // subFaderPresent\n            0,     // faderOffset\n            32,    // selectOffset\n            48,    // muteOffset\n            64,    // recordOffset\n            16,    // subFaderOffset\n            MidiCommandCode.ControlChange, // faderCode\n            MidiCommandCode.ControlChange, // selectCode\n            MidiCommandCode.ControlChange, // muteCode\n            MidiCommandCode.ControlChange, // recordCode\n            MidiCommandCode.ControlChange  // subFaderCode\n        );\n\n        public NanoKontrol2(AudioDevice audioDev)\n        {\n            audioDevices = audioDev;\n            FindMidiIn();\n            FindMidiOut();\n            if (Found)\n            {\n                ResetAllLights();\n                InitFaders();\n                InitButtons();\n                LightShow();\n                LoadAssignments();\n                ListenForMidi();\n            }\n        }\n\n        public override void ResetAllLights()\n        {\n            foreach (var i in Enumerable.Range(0, 128))\n                midiOut.Send(new ControlChangeEvent(0, 1, (MidiController)i, 0).GetAsShortMessage());\n        }\n\n        public override void SetLight(int controller, bool state)\n        {\n            midiOut.Send(new ControlChangeEvent(0, 1, (MidiController)(controller), state ? 127 : 0).GetAsShortMessage());\n        }\n\n        public override void InitFaders()\n        {\n            faders = new List<Fader>();\n            foreach (var i in Enumerable.Range(0, 8))\n            {\n                Fader fader = new Fader(this, i);\n                fader.ResetLights();\n                faders.Add(fader);\n            }\n        }\n\n        public override void InitButtons()\n        {\n            buttons = new List<Button>();\n            buttons.Add(new Button(ref midiOut,  ButtonType.MediaPrevious, 43, true));\n            buttons.Add(new Button(ref midiOut,  ButtonType.MediaNext,     44, true));\n            buttons.Add(new Button(ref midiOut,  ButtonType.MediaStop,     42, false));\n            buttons.Add(new Button(ref midiOut,  ButtonType.MediaPlay,     41, true));\n            buttons.Add(new Button(ref midiOut,  ButtonType.MediaRecord,   45, false));\n\n            buttonsMappingTable = new Hashtable();\n            foreach (var button in buttons)\n            {\n                buttonsMappingTable.Add(button.controller, button);\n            }\n        }\n\n        public override void LightShow()\n        {\n            List<LightShowBackup> lightBackups = new List<LightShowBackup>();\n\n            //backup settings and turn them all off\n            foreach (var fader in faders)\n            {\n                lightBackups.Add(new LightShowBackup(fader));\n                fader.SetSelectLight(false);\n                fader.SetSelectLight(false);\n                fader.SetMuteLight(false);\n                fader.SetRecordLight(false);\n            }\n            foreach (var button in buttons)\n            {\n                lightBackups.Add(new LightShowBackup(button));\n                button.SetLight(false);\n            }\n\n            //do light show\n            int travelSpeed = 50;\n            foreach (var button in buttons)\n            {\n                button.SetLight(true);\n                System.Threading.Thread.Sleep(travelSpeed);\n                button.SetLight(false);\n            }\n            foreach (var fader in faders)\n            {\n                fader.SetSelectLight(true);\n                fader.SetMuteLight(true);\n                fader.SetRecordLight(true);\n                System.Threading.Thread.Sleep(travelSpeed);\n                fader.SetSelectLight(false);\n                fader.SetMuteLight(false);\n                fader.SetRecordLight(false);\n            }\n            //reverse\n            for (int i = faders.Count - 1; i >= 0; i--)\n            {\n                var fader = faders[i];\n                fader.SetSelectLight(true);\n                fader.SetMuteLight(true);\n                fader.SetRecordLight(true);\n                System.Threading.Thread.Sleep(travelSpeed);\n            }\n            for (int i = buttons.Count - 1; i >= 0; i--)\n            {\n                var button = buttons[i];\n                button.SetLight(true);\n                System.Threading.Thread.Sleep(travelSpeed);\n            }\n            //flash\n            /*\n            for (int i = 2; i > 0; i--)\n            {\n                System.Threading.Thread.Sleep(travelSpeed * 2);\n\n                if (i != 3)\n                {\n                    foreach (var button in buttons)\n                    {\n                        button.SetLight(true);\n                    }\n                    foreach (var fader in faders)\n                    {\n                        fader.SetSelectLight(true);\n                        fader.SetMuteLight(true);\n                        fader.SetRecordLight(true);\n                    }\n                }\n\n                System.Threading.Thread.Sleep(travelSpeed * 2);\n\n                foreach (var button in buttons)\n                {\n                    button.SetLight(false);\n                }\n                foreach (var fader in faders)\n                {\n                    fader.SetSelectLight(false);\n                    fader.SetMuteLight(false);\n                    fader.SetRecordLight(false);\n                }\n            }\n\n            foreach (var button in buttons)\n            {\n                button.SetLight(true);\n            }\n            */\n\n            //reset settings\n            foreach (var lightBackup in lightBackups)\n            {\n                lightBackup.reset();\n            }\n\n        }\n\n        private class LightShowBackup\n        {\n            private bool[] lightSettings;\n            private Fader fader = null;\n            private Button button = null;\n\n            public LightShowBackup(Fader inFader)\n            {\n                lightSettings = new bool[3];\n                lightSettings[0] = inFader.GetSelectLight();\n                lightSettings[1] = inFader.GetMuteLight();\n                lightSettings[2] = inFader.GetRecordLight();\n                fader = inFader;\n            }\n\n            public LightShowBackup(Button inButton)\n            {\n                lightSettings = new bool[1];\n                lightSettings[0] = inButton.GetLight();\n                button = inButton;\n            }\n\n            public void reset()\n            {\n                if (fader != null)\n                {\n                    fader.SetSelectLight(lightSettings[0]);\n                    fader.SetMuteLight(lightSettings[1]);\n                    fader.SetRecordLight(lightSettings[2]);\n                }\n                else if (button != null)\n                {\n                    button.SetLight(lightSettings[0]);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "NK2Tray/OP1.cs",
    "content": "using NAudio.Midi;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace NK2Tray\n{\n    public class OP1 : MidiDevice\n    {\n        public override string SearchString => \"op-1\";\n\n        public FaderDef FirstFader => new FaderDef(\n            false,   // delta\n            127f,    // range\n            1,      // channel\n            true,   // selectPresent\n            true,   // mutePresent\n            true,  // recordPresent\n            false, // subFaderPresent\n            1,      // faderOffset\n            64,     // selectOffset\n            50,     // muteOffset\n            51,     // recordOffset\n            0,      // subFaderOffset\n            MidiCommandCode.ControlChange,  // faderCode\n            MidiCommandCode.ControlChange,  // selectCode\n            MidiCommandCode.ControlChange,  // muteCode\n            MidiCommandCode.ControlChange,  // recordCode\n            MidiCommandCode.ControlChange   // subFaderCode\n        );\n\n        public FaderDef SecondFader => new FaderDef(\n            false,   // delta\n            127f,    // range\n            1,      // channel\n            true,   // selectPresent\n            true,   // mutePresent\n            true,  // recordPresent\n            false, // subFaderPresent\n            1,      // faderOffset\n            64,     // selectOffset\n            51,     // muteOffset\n            20,     // recordOffset\n            0,      // subFaderOffset\n            MidiCommandCode.ControlChange,  // faderCode\n            MidiCommandCode.ControlChange,  // selectCode\n            MidiCommandCode.ControlChange,  // muteCode\n            MidiCommandCode.ControlChange,  // recordCode\n            MidiCommandCode.ControlChange   // subFaderCode\n        );\n\n        public FaderDef ThirdFader => new FaderDef(\n            false,   // delta\n            127f,    // range\n            1,      // channel\n            true,   // selectPresent\n            true,   // mutePresent\n            true,  // recordPresent\n            false, // subFaderPresent\n            1,      // faderOffset\n            64,     // selectOffset\n            20,     // muteOffset\n            21,     // recordOffset\n            0,      // subFaderOffset\n            MidiCommandCode.ControlChange,  // faderCode\n            MidiCommandCode.ControlChange,  // selectCode\n            MidiCommandCode.ControlChange,  // muteCode\n            MidiCommandCode.ControlChange,  // recordCode\n            MidiCommandCode.ControlChange   // subFaderCode\n        );\n\n        public FaderDef FourthFader => new FaderDef(\n            false,   // delta\n            127f,    // range\n            1,      // channel\n            true,   // selectPresent\n            true,   // mutePresent\n            true,  // recordPresent\n            false,  // subFaderPresent\n            1,      // faderOffset\n            64,     // selectOffset\n            21,     // muteOffset\n            22,     // recordOffset\n            0,      // subFaderOffset\n            MidiCommandCode.ControlChange,  // faderCode\n            MidiCommandCode.ControlChange,  // selectCode\n            MidiCommandCode.ControlChange,  // muteCode\n            MidiCommandCode.ControlChange,  // recordCode\n            MidiCommandCode.ControlChange   // subFaderCode\n        );\n\n        public OP1(AudioDevice audioDev)\n        {\n            audioDevices = audioDev;\n            FindMidiIn();\n            FindMidiOut();\n\n            if (Found)\n            {\n                InitFaders();\n                InitButtons();\n                LoadAssignments();\n                ListenForMidi();\n            }\n        }\n\n        public override void InitFaders()\n        {\n            faders = new List<Fader>\n            {\n                new Fader(this, 0, FirstFader),\n                new Fader(this, 1, SecondFader),\n                new Fader(this, 2, ThirdFader),\n                new Fader(this, 3, FourthFader)\n            };\n        }\n\n        public override void InitButtons()\n        {\n            buttons = new List<Button>\n            {\n                new Button(ref midiOut, ButtonType.MediaPlay, 39, true),\n                new Button(ref midiOut, ButtonType.MediaStop, 40, false),\n                new Button(ref midiOut, ButtonType.MediaNext, 16, true),\n                new Button(ref midiOut, ButtonType.MediaPrevious, 15, true)\n            };\n\n            // is this still needed?\n            buttonsMappingTable = new Hashtable();\n\n            foreach (var button in buttons)\n            {\n                buttonsMappingTable.Add(button.controller, button);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "NK2Tray/Program.cs",
    "content": "﻿using NAudio.CoreAudioApi;\nusing System;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.Linq;\nusing System.Threading;\nusing System.Windows.Forms;\nusing System.Windows.Threading;\nusing NAudio;\n\nnamespace NK2Tray\n{\n    public class SysTrayApp : Form\n    {\n        [STAThread]\n        public static void Main() => Application.Run(new SysTrayApp());\n\n        private NotifyIcon trayIcon;\n        public MidiDevice midiDevice;\n        public AudioDevice audioDevices;\n        public bool logarithmic;\n\n        private Dispatcher _workerDispatcher;\n        private Thread _workerThread;\n\n        public SysTrayApp()\n        {\n            System.AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionTrapper;\n            Console.WriteLine($@\"NK2 Tray {DateTime.Now}\");\n\n            // Set up a worker thread to always run SetupDevice and PopUp inside of\n            _workerThread = new Thread(new ThreadStart(() =>\n            {\n                _workerDispatcher = Dispatcher.CurrentDispatcher;\n                Dispatcher.Run();\n            }));\n\n            _workerThread.Start();\n\n            trayIcon = new NotifyIcon\n            {\n                Text = \"NK2 Tray\",\n                Icon = new Icon(Properties.Resources.nk2tray, 40, 40),\n                ContextMenu = new ContextMenu()\n            };\n\n            trayIcon.ContextMenu.Popup += (object sender, EventArgs e) =>\n                _workerDispatcher.Invoke(() => OnPopup(sender, e));\n\n            trayIcon.Visible = true; \n            \n            while (_workerDispatcher == null)\n            {\n\n                /*\n                 * weird threading situation.\n                 * _workerDispatcher = Dispatcher.CurrentDispatcher; and Dispatcher.Run(); must be set in another thread otherwise the gui doesn't work or the program doesn't exit cleanly.\n                 * but on faster machines we race to Invoke(SetupDevice); before the other thread has instantiated the _workerDispatcher\n                 * easy way to solve is to just wait here until _workerDispatcher is set \n                 */\n\n                Thread.Sleep(10);\n            }\n\n            _workerDispatcher.Invoke(SetupDevice);\n        }\n\n        private Boolean SetupDevice()\n        {\n            audioDevices = new AudioDevice();\n\n            midiDevice = new NanoKontrol2(audioDevices);\n\n            if (!midiDevice.Found)\n                midiDevice = new XtouchMini(audioDevices);\n\n            if (!midiDevice.Found)\n                midiDevice = new OP1(audioDevices);\n\n             if (!midiDevice.Found)\n               midiDevice = new EasyControl(audioDevices);\n\n\n            audioDevices.midiDevice = midiDevice;\n\n            logarithmic = System.Convert.ToBoolean(ConfigSaver.GetAppSettings(\"logarithmic\"));\n            SaveLogarithmic();\n\n            return midiDevice.Found;\n        }\n\n        private void UnhandledExceptionTrapper(object sender, UnhandledExceptionEventArgs e)\n        {\n            Console.WriteLine(e.ExceptionObject.ToString());\n            MessageBox.Show(e.ExceptionObject.ToString(), \"NK2 Tray Error\", MessageBoxButtons.OK);\n\n            if (midiDevice != null)\n            {\n                try\n                {\n                    midiDevice.ResetAllLights();\n                    midiDevice.faders.Last().SetRecordLight(true);\n                }\n                catch (Exception ex)\n                {\n                    Console.WriteLine(ex.ToString());\n                }\n            }\n            Application.Exit();\n        }\n\n        private String getProgramLabel(Fader fader)\n        {\n            if (fader.assigned)\n                return fader.assignment.label;\n            \n            if(fader.identifier != null && fader.identifier.Length > 0 && fader.identifier.Contains(\".exe\"))\n            {\n                String identifier = fader.identifier;\n                int lastBackSlash = identifier.LastIndexOf('\\\\') + 1;\n                int programNameLength = identifier.IndexOf(\".exe\") - lastBackSlash;\n                String progamName = identifier.Substring(lastBackSlash, programNameLength);\n                return progamName;\n            }\n            return \"\";\n        }\n\n        private void OnPopup(object sender, EventArgs e)\n        {\n            ContextMenu trayMenu = (ContextMenu)sender;\n\n            // Clean old menu items out\n            var oldMenuItems = trayMenu.MenuItems.Cast<MenuItem>().ToArray();\n            foreach (var item in oldMenuItems)\n                item.Dispose();\n\n            trayMenu.MenuItems.Clear();\n\n            var mixerSessions = audioDevices.GetCachedMixerSessions();\n\n            var masterMixerSessionList = new List<MixerSession>();\n            foreach(MMDevice mmDevice in audioDevices.outputDevices)\n            {\n                masterMixerSessionList.Add(new MixerSession(mmDevice.ID, audioDevices, \"Master\", SessionType.Master));\n            }\n\n            /*\n            // Commented out Iput device code because it breaks the session lists when input and ouput is controlled at the same time\n            var micMixerSessionList = new List<MixerSession>();\n            foreach (MMDevice mmDevice in audioDevices.inputDevices)\n            {\n                micMixerSessionList.Add(new MixerSession(mmDevice.ID, audioDevices, \"Microphone\", SessionType.Master));\n            }\n            */\n\n            MixerSession focusMixerSession;\n            focusMixerSession = new MixerSession(\"\", audioDevices, \"Focus\", SessionType.Focus);\n                        \n            // Dont create context menu if no midi device is connected\n            if(!midiDevice.Found)\n            {\n                if (!SetupDevice()) // This setup call can be removed once proper lifecycle management is implemented, for now this also adds a nice way to reconnect the controller\n                {\n                    MessageBox.Show(\"No midi device detected. Are you sure your device is plugged in correctly?\");\n                    return;\n                }\n            }\n                       \n            foreach (var fader in midiDevice.faders)\n            {\n                MenuItem faderMenu = new MenuItem($@\"Fader {fader.faderNumber + 1} - \" + getProgramLabel(fader));\n                trayMenu.MenuItems.Add(faderMenu);\n\n                // Add master mixerSession to menu\n                foreach(MixerSession mixerSession in masterMixerSessionList)\n                {\n                    MenuItem masterItem = new MenuItem(mixerSession.label, AssignFader);\n                    masterItem.Tag = new object[] { fader, mixerSession };\n                    faderMenu.MenuItems.Add(masterItem);\n                }\n\n                /* \n                // Commented out Iput device code because it breaks the session lists when input and ouput is controlled at the same time\n                faderMenu.MenuItems.Add(\"-\");\n\n                foreach (MixerSession mixerSession in micMixerSessionList)\n                {\n                    MenuItem micItem = new MenuItem(mixerSession.label, AssignFader);\n                    micItem.Tag = new object[] { fader, mixerSession };\n                    faderMenu.MenuItems.Add(micItem);\n                }\n                */\n\n                faderMenu.MenuItems.Add(\"-\");\n\n                // Add focus mixerSession to menu                \n                MenuItem focusItem = new MenuItem(focusMixerSession.label, AssignFader);\n                focusItem.Tag = new object[] { fader, focusMixerSession };\n                faderMenu.MenuItems.Add(focusItem);\n\n                faderMenu.MenuItems.Add(\"-\");\n\n                // Add application mixer sessions to each fader\n                foreach (var mixerSession in mixerSessions)\n                {\n                    MenuItem si = new MenuItem(mixerSession.label, AssignFader);\n                    si.Tag = new object[] { fader, mixerSession };\n                    faderMenu.MenuItems.Add(si);\n                }\n\n                faderMenu.MenuItems.Add(\"-\");\n\n                // Add unassign option\n                MenuItem unassignItem = new MenuItem(\"Unassign\", UnassignFader);\n                unassignItem.Tag = new object[] { fader };\n                faderMenu.MenuItems.Add(unassignItem);                \n            }\n\n            trayMenu.MenuItems.Add(\"-\");\n\n            // Add toggle option for logarithmic volume curve\n            MenuItem logCheck = new MenuItem(\"Logarithmic\", ToggleLogarithmic);\n            logCheck.Checked = logarithmic;\n            trayMenu.MenuItems.Add(logCheck);\n\n            trayMenu.MenuItems.Add(\"-\");\n            trayMenu.MenuItems.Add(\"Exit\", OnExit);\n        }\n\n        private void ToggleLogarithmic(object sender, EventArgs e)\n        {\n            logarithmic = !logarithmic;\n            ConfigSaver.AddOrUpdateAppSettings(\"logarithmic\", System.Convert.ToString(logarithmic));\n            SaveLogarithmic();\n        }\n\n        private void SaveLogarithmic()\n        {\n            midiDevice.SetCurve(logarithmic ? 2f : 1f);\n        }\n\n        private void AssignFader(object sender, EventArgs e)\n        {\n            var fader = (Fader)((object[])((MenuItem)sender).Tag)[0];\n            var mixerSession = (MixerSession)((object[])((MenuItem)sender).Tag)[1];\n            fader.Assign(mixerSession);\n            midiDevice.SaveAssignments();\n        }\n\n        private void UnassignFader(object sender, EventArgs e)\n        {\n            var fader = (Fader)((object[])((MenuItem)sender).Tag)[0];\n            fader.Unassign();\n            midiDevice.SaveAssignments();\n        }\n\n        protected override void OnLoad(EventArgs e)\n        {\n            Visible = false; // Hide form window.\n            ShowInTaskbar = false; // Remove from taskbar.\n\n            base.OnLoad(e);\n        }\n\n        private void OnExit(object sender, EventArgs e)\n        {\n            try\n            {\n                midiDevice.ResetAllLights();\n                midiDevice.SaveAssignments();\n            }\n            catch (MmException ex)\n            {\n                if (ex.Message.StartsWith(\"InvalidHandle calling midiOutShortMsg\"))\n                {\n                    // Exit program safely if device was already disconnected\n                }\n            }\n\n            Application.Exit();\n            _workerDispatcher.InvokeShutdown();\n        }\n\n    }\n}\n"
  },
  {
    "path": "NK2Tray/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Information about an assembly is controlled through the following\n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"NK2Tray\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"NK2Tray\")]\n[assembly: AssemblyCopyright(\"Copyright ©  2019\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// Setting ComVisible to false makes the types in this assembly not visible\n// to COM components.  If you need to access a type in this assembly from\n// COM, set the ComVisible attribute to true on that type.\n[assembly: ComVisible(false)]\n\n// The following GUID is for the ID of the typelib if this project is exposed to COM\n[assembly: Guid(\"f88d8f42-cc15-40ae-9301-043313764c4c\")]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version\n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers\n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"0.0.16.0\")]\n[assembly: AssemblyFileVersion(\"0.0.16.0\")]\n"
  },
  {
    "path": "NK2Tray/Properties/Resources.Designer.cs",
    "content": "﻿//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//     Runtime Version:4.0.30319.42000\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\n\nnamespace NK2Tray.Properties {\n    using System;\n    \n    \n    /// <summary>\n    ///   A strongly-typed resource class, for looking up localized strings, etc.\n    /// </summary>\n    // This class was auto-generated by the StronglyTypedResourceBuilder\n    // class via a tool like ResGen or Visual Studio.\n    // To add or remove a member, edit your .ResX file then rerun ResGen\n    // with the /str option, or rebuild your VS project.\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Resources.Tools.StronglyTypedResourceBuilder\", \"15.0.0.0\")]\n    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\n    internal class Resources {\n        \n        private static global::System.Resources.ResourceManager resourceMan;\n        \n        private static global::System.Globalization.CultureInfo resourceCulture;\n        \n        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute(\"Microsoft.Performance\", \"CA1811:AvoidUncalledPrivateCode\")]\n        internal Resources() {\n        }\n        \n        /// <summary>\n        ///   Returns the cached ResourceManager instance used by this class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Resources.ResourceManager ResourceManager {\n            get {\n                if (object.ReferenceEquals(resourceMan, null)) {\n                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager(\"NK2Tray.Properties.Resources\", typeof(Resources).Assembly);\n                    resourceMan = temp;\n                }\n                return resourceMan;\n            }\n        }\n        \n        /// <summary>\n        ///   Overrides the current thread's CurrentUICulture property for all\n        ///   resource lookups using this strongly typed resource class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Globalization.CultureInfo Culture {\n            get {\n                return resourceCulture;\n            }\n            set {\n                resourceCulture = value;\n            }\n        }\n        \n        /// <summary>\n        ///   Looks up a localized resource of type System.Drawing.Icon similar to (Icon).\n        /// </summary>\n        internal static System.Drawing.Icon nk2tray {\n            get {\n                object obj = ResourceManager.GetObject(\"nk2tray\", resourceCulture);\n                return ((System.Drawing.Icon)(obj));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "NK2Tray/Properties/Resources.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <assembly alias=\"System.Windows.Forms\" name=\"System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\" />\n  <data name=\"nk2tray\" type=\"System.Resources.ResXFileRef, System.Windows.Forms\">\n    <value>..\\nk2tray.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>\n  </data>\n</root>"
  },
  {
    "path": "NK2Tray/Properties/Settings.Designer.cs",
    "content": "﻿//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//     Runtime Version:4.0.30319.42000\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\n\nnamespace NK2Tray.Properties {\n    \n    \n    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator\", \"15.9.0.0\")]\n    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {\n        \n        private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));\n        \n        public static Settings Default {\n            get {\n                return defaultInstance;\n            }\n        }\n\n        public string SavedAssignments { get; internal set; }\n    }\n}\n"
  },
  {
    "path": "NK2Tray/Properties/Settings.settings",
    "content": "﻿<?xml version='1.0' encoding='utf-8'?>\n<SettingsFile xmlns=\"http://schemas.microsoft.com/VisualStudio/2004/01/settings\" CurrentProfile=\"(Default)\">\n  <Profiles>\n    <Profile Name=\"(Default)\" />\n  </Profiles>\n  <Settings />\n</SettingsFile>\n"
  },
  {
    "path": "NK2Tray/WindowTools.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\nusing System.Runtime.InteropServices;\n\nnamespace NK2Tray\n{\n    class WindowTools\n    {\n        [DllImport(\"user32.dll\")]\n        public static extern IntPtr FindWindow(string strClassName, string strWindowName);\n\n        [DllImport(\"user32.dll\")]\n        public static extern IntPtr GetForegroundWindow();\n\n        [DllImport(\"user32.dll\", SetLastError = true)]\n        public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);\n\n        public static int GetPidByName(string name)\n        {\n            Process[] processes = Process.GetProcessesByName(name);\n            int pid = 0;\n            int maxHandleCount = 0;\n            foreach (Process process in processes)\n            {\n                if (process.Id != 0 && process.HandleCount > maxHandleCount)\n                {\n                    maxHandleCount = process.HandleCount;\n                    pid = process.Id;\n                }\n            }\n            return pid;\n            /*{\n                var hWnd = FindWindow(name, \"\");\n                if (hWnd == IntPtr.Zero)\n                    return 0;\n\n                uint pID;\n                GetWindowThreadProcessId(hWnd, out pID);\n                if (pID == 0)\n                    return 0;\n\n                Console.WriteLine(pID);\n                return Convert.ToInt32(pID);\n            }*/\n\n        }\n\n        public static int GetForegroundPID()\n        {\n            var hWnd = GetForegroundWindow();\n            if (hWnd == IntPtr.Zero)\n                return 0;\n\n            uint pID;\n            GetWindowThreadProcessId(hWnd, out pID);\n            if (pID == 0)\n                return 0;\n\n            return Convert.ToInt32(pID);\n        }\n\n        public static bool ProcessExists(uint processId)\n        {\n            try\n            {\n                var process = Process.GetProcessById((int)processId);\n                return true;\n            }\n            catch (ArgumentException)\n            {\n                return false;\n            }\n        }\n\n        public static void Dump(object ob)\n        {\n            Console.WriteLine(\"================\");\n            foreach (var prop in ob.GetType().GetProperties())\n                Console.WriteLine($@\"{prop.Name} = {prop.GetValue(ob, null)}\");\n        }\n\n        public static bool IsProcessByNameRunning(string processName)\n        {\n            return GetPidByName(processName) != 0;\n        }\n\n        public static void StartApplication(string applicationPath)\n        {\n            try\n            {\n                Process.Start(new ProcessStartInfo(applicationPath));\n            }\n            catch (InvalidOperationException)\n            {\n                // Application cannot be started for this button\n            } \n        }\n    }\n}\n"
  },
  {
    "path": "NK2Tray/XtouchMini.cs",
    "content": "﻿using NAudio.Midi;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Collections;\n\nnamespace NK2Tray\n{\n    public class XtouchMini : MidiDevice\n    {\n        public override string SearchString => \"x-touch mini\";\n        public override FaderDef DefaultFaderDef => new FaderDef(\n            true,  // delta\n            64f,   // range\n            1,     // channel\n            true,  // selectPresent\n            true,  // mutePresent\n            false, // recordPresent\n            false, // subFaderPresent\n            16,    // faderOffset\n            32,    // selectOffset\n            38,    // muteOffset\n            0,     // recordOffset\n            0,     // subFaderOffset\n            MidiCommandCode.ControlChange, // faderCode\n            MidiCommandCode.NoteOn,        // selectCode\n            MidiCommandCode.NoteOn,        // muteCode\n            MidiCommandCode.ControlChange, // recordCode\n            MidiCommandCode.ControlChange  // subFaderCode\n        );\n\n        public FaderDef FirstTwoFaderDef => new FaderDef(\n            true,  // delta\n            64f,   // range\n            1,     // channel\n            true,  // selectPresent\n            true,  // mutePresent\n            false, // recordPresent\n            false, // subFaderPresent\n            16,    // faderOffset\n            32,    // selectOffset\n            89,    // muteOffset\n            0,     // recordOffset\n            0,     // subFaderOffset\n            MidiCommandCode.ControlChange, // faderCode\n            MidiCommandCode.NoteOn,        // selectCode\n            MidiCommandCode.NoteOn,        // muteCode\n            MidiCommandCode.ControlChange, // recordCode\n            MidiCommandCode.ControlChange  // subFaderCode\n        );\n\n        public FaderDef MasterFaderDef => new FaderDef(\n            false,  // delta\n            16256f, // range\n            1,      // channel\n            true,   // selectPresent\n            true,   // mutePresent\n            false,  // recordPresent\n            false,  // subFaderPresent\n            0,      // faderOffset\n            76,     // selectOffset\n            77,     // muteOffset\n            0,      // recordOffset\n            0,      // subFaderOffset\n            MidiCommandCode.PitchWheelChange, // faderCode\n            MidiCommandCode.NoteOn,           // selectCode\n            MidiCommandCode.NoteOn,           // muteCode\n            MidiCommandCode.ControlChange,    // recordCode\n            MidiCommandCode.ControlChange,    // subFaderCode\n            9      // faderChannelOverride\n        );\n\n        public XtouchMini(AudioDevice audioDev)\n        {\n            audioDevices = audioDev;\n            FindMidiIn();\n            FindMidiOut();\n            if (Found)\n            {\n                ResetAllLights();\n                InitFaders();\n                InitButtons();\n                LoadAssignments();\n                ListenForMidi();\n            }\n        }\n\n        public override void SetVolumeIndicator(int faderNum, float level)\n        {\n            if (level >= 0)\n            {\n                var usedLevel = level;\n                var fader = faders[faderNum];\n\n                if (fader.faderDef.delta)\n                {\n                    var nearestStep = fader.steps.Select((x, i) => new { Index = i, Distance = Math.Abs(level - x) }).OrderBy(x => x.Distance).First().Index;\n                    usedLevel = (float)nearestStep / (fader.steps.Length - 1);\n                }\n\n                var val = (int)Math.Round(usedLevel * 12) + 1 + 16 * 2;\n\n                Console.WriteLine($@\"Setting fader {fader} display to {usedLevel} ({val})\");\n                midiOut.Send(new ControlChangeEvent(0, 1, (MidiController)(faderNum + 48), val).GetAsShortMessage());\n            }\n            else\n                midiOut.Send(new ControlChangeEvent(0, 1, (MidiController)(faderNum + 48), 0).GetAsShortMessage());\n        }\n\n        public override void ResetAllLights()\n        {\n\n            foreach (var i in Enumerable.Range(48, 8))\n                midiOut.Send(new ControlChangeEvent(0, 1, (MidiController)i, 0).GetAsShortMessage());\n\n\n            foreach (var i in Enumerable.Range(0, 128))\n                midiOut.Send(new NoteOnEvent(0, 1, i, 0, 0).GetAsShortMessage());\n        }\n\n        public override void SetLight(int controller, bool state)\n        {\n            midiOut.Send(new NoteOnEvent(0, 1, controller, state ? 127 : 0, 0).GetAsShortMessage());\n        }\n\n        public override void InitFaders()\n        {\n            faders = new List<Fader>();\n            \n            foreach (var i in Enumerable.Range(0, 9))\n            {\n                Fader fader = new Fader(this, i, SelectFaderDef(i));\n                fader.ResetLights();\n                faders.Add(fader);\n            }\n        }\n\n        public FaderDef SelectFaderDef(int faderNum)\n        {\n            if (faderNum < 2)\n                return FirstTwoFaderDef;\n            else if (faderNum == 8)\n                return MasterFaderDef;\n            else\n                return DefaultFaderDef;\n        }\n\n        public override void InitButtons()\n        {\n            buttons = new List<Button>();\n\n            buttons.Add(new Button(ref midiOut,  ButtonType.MediaPrevious, 91, true,  MidiCommandCode.NoteOn));\n            buttons.Add(new Button(ref midiOut,  ButtonType.MediaNext,     92, true,  MidiCommandCode.NoteOn));\n            buttons.Add(new Button(ref midiOut,  ButtonType.MediaStop,     93, false, MidiCommandCode.NoteOn));\n            buttons.Add(new Button(ref midiOut,  ButtonType.MediaPlay,     94, true,  MidiCommandCode.NoteOn));\n            buttons.Add(new Button(ref midiOut,  ButtonType.MediaRecord,   95, false, MidiCommandCode.NoteOn));\n\n            buttonsMappingTable = new Hashtable();\n            foreach (var button in buttons)\n            {\n                buttonsMappingTable.Add(button.controller, button);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "NK2Tray/packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n  <package id=\"Costura.Fody\" version=\"3.3.0\" targetFramework=\"net461\" />\n  <package id=\"Fody\" version=\"3.3.5\" targetFramework=\"net461\" developmentDependency=\"true\" />\n  <package id=\"NAudio\" version=\"1.8.5\" targetFramework=\"net461\" />\n</packages>"
  },
  {
    "path": "NK2Tray.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 15\nVisualStudioVersion = 15.0.28307.168\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"NK2Tray\", \"NK2Tray\\NK2Tray.csproj\", \"{F88D8F42-CC15-40AE-9301-043313764C4C}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{F88D8F42-CC15-40AE-9301-043313764C4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F88D8F42-CC15-40AE-9301-043313764C4C}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F88D8F42-CC15-40AE-9301-043313764C4C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F88D8F42-CC15-40AE-9301-043313764C4C}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {1808D8FF-F1C2-4A1F-A929-E9F148BFA9A1}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "NK2Tray_Display/BOM.md",
    "content": "## Bill of materials for the NK2Tray_Display\n\n\n\n### Printed Parts:\n\n 1x  \tNK2DisplayCaseA.stl\n\n 1x \tNK2DisplayCaseB.stl\n\n 3x  \tNK2DisplayLatch.stl\n\nAs the case and the latches do not bear any load, you can use a low infill. 25% is more than enough. Use 2-3 perimeter walls The case is designed to be printed with the face on the print bed, that should get you a nice surface to look at.\nPrint the latches as they are designed and use supports under the overhang. Use at least 3 perimeter walls, again infill doesn´t matter that much.\n\n\n\n### Electronic  Parts:\n\n8x OLED Display 0.96 inch, 128X64, I2C (get the white OR blue ones, not yellow&blue)\nhttps://www.aliexpress.com/item/32713614136.html?spm=a2g0s.9042311.0.0.27424c4dUOH4Fo\n\n1x Wemos D1 Mini V3 \nhttps://www.aliexpress.com/item/32855727444.html?spm=a2g0s.9042311.0.0.27424c4dq7waX2\n\n1x Adafruit TCA9548A I2C Multiplexer\nhttps://www.amazon.de/gp/product/B017C09ETS/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1\n\n1x Custom PCB\nGerber_PCB_NK2Tray_Display.zip\n\n\n\n### Fastener:\n\n3x M3x8 Hex Socket screw or similar\n\n\n\n### Firmware:\n\nNK2Tray_DisplayFW.ino\n"
  },
  {
    "path": "NK2Tray_Display/NK2Tray_DisplayFW.ino",
    "content": "// Display Firmware V2\n// I2C Adressen:\n// Oled: 0x3C\n// Multi:0x70\n\n#include \"Wire.h\"               // Hmmm?\n#include \"ssd1306.h\"            // 128x64 Display Ansteuerung\n#define MUX_Address 0x70        // TCA9548A Multiplexer Adresse\n#include <ESP8266WiFi.h>        // Include the Wi-Fi library\n#include <ESP8266Ping.h>        // Include the Ping library\n\n\nconst char* ssid     = \"Skynet Apocalypse\";         // The SSID (name) of the Wi-Fi network you want to connect to\nconst char* password = \"chaotisch\";                 // The password of the Wi-Fi network\nconst IPAddress remote_ip(192, 168, 178, 69);       // Zieladresse\n\n\n// Anzuzeigende Bilder:\nconst unsigned char WinLogo [] = {\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x80, 0xC0, 0xC0, 0xE0, 0xE0, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0xE0,\n0xC0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xF8,\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n0xFF, 0x1F, 0x03, 0x00, 0x00, 0x00, 0xF0, 0xFC, 0xF8, 0xF8, 0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0xE0,\n0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xF0, 0xF0, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x38, 0x3F, 0x1F,\n0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x3F, 0x3F, 0x7F, 0x7F, 0xFF, 0x0F,\n0x03, 0x00, 0x00, 0x80, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xF0, 0xF8, 0xF8, 0xFC, 0xFC,\n0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF0, 0x70, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x07, 0x0F, 0x0F, 0x0F, 0x1F, 0x1F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,\n0x3F, 0x1F, 0x1F, 0x0F, 0x0F, 0x0F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x0F, 0x00, 0x00, 0x00, 0xD0,\n0xFC, 0xFF, 0xFF, 0xFE, 0xFE, 0xFC, 0xFC, 0xFC, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xFC,\n0xFC, 0xFC, 0xFC, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0F, 0x0F, 0x07, 0x07, 0x07, 0x07, 0x03, 0x03, 0x03,\n0x03, 0x07, 0x07, 0x07, 0x0F, 0x0F, 0x0F, 0x1F, 0x3F, 0x07, 0x00, 0x00, 0x00, 0xF0, 0xFE, 0xFF,\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n0x3F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03,\n0x03, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x03, 0x01, 0x01,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n};\n\nconst unsigned char ChromeLogo [] = {\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x80, 0x80, 0xC0, 0xE0, 0xE0, 0xF0, 0xF0, 0xF0, 0xF8, 0xF8, 0xF8, 0xF8, 0xFC, 0xFC, 0xFC,\n0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF8, 0xF8, 0xF8, 0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0x80,\n0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x3C, 0xFE,\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x7F,\n0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,\n0x7F, 0x7F, 0x7E, 0x7C, 0x78, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xF8, 0xFF, 0xFF, 0xFF, 0xFE, 0xF8, 0xE0,\n0x81, 0x07, 0x1F, 0x3F, 0xFF, 0x7F, 0x1F, 0x0F, 0x83, 0xC1, 0xF1, 0xF0, 0xF8, 0xFC, 0xFC, 0xFC,\n0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF0, 0xF0, 0xC0, 0x80, 0x04, 0x1C, 0x7C, 0xFC, 0xFC, 0xFC,\n0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n0xFF, 0xFF, 0xFC, 0xF0, 0xC0, 0x80, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF,\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFC, 0xF0, 0xF0, 0xE3, 0xC3, 0xC7, 0x8F, 0x8F, 0x8F,\n0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x07, 0x03, 0x03, 0xC0, 0xE0, 0xF8, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x0F, 0x1F,\n0x3F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n0x7F, 0x1F, 0x07, 0x81, 0xE0, 0xF8, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,\n0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x03, 0x03, 0x07, 0x07, 0x07, 0x0F, 0x0F, 0x03, 0x00,\n0x00, 0x0C, 0x0E, 0x0F, 0x0F, 0x0F, 0x07, 0x07, 0x07, 0x03, 0x03, 0x03, 0x01, 0x01, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n};\n\nconst unsigned char DiscordLogo [] = {\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xE0, 0xF0,\n0x70, 0x70, 0x38, 0x38, 0x18, 0x18, 0x18, 0x9C, 0x8C, 0x88, 0x80, 0x80, 0xC0, 0xC0, 0xC0, 0xC0,\n0xC0, 0xC0, 0xC0, 0xC0, 0x80, 0x80, 0x88, 0x8C, 0x9C, 0x18, 0x18, 0x18, 0x38, 0x38, 0x70, 0x70,\n0xF0, 0xE0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xF8, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFC,\n0xFC, 0xFC, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFC, 0xFC,\n0xFC, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xF8, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x80, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x3F, 0x1F, 0x3F, 0x3F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x3F, 0x1F, 0x3F, 0x3F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF,\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x80, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n0xFF, 0xFF, 0xFF, 0xF1, 0xC0, 0x80, 0x80, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF,\n0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x80, 0x80, 0xC0, 0xF1, 0xFF, 0xFF, 0xFF,\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xC7, 0x8F, 0x8F,\n0x1F, 0x1F, 0x3F, 0x3F, 0x7F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x7F, 0x3F, 0x3F, 0x1F, 0x1F,\n0x8F, 0x8F, 0xC7, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x07, 0x0F, 0x0F, 0x0F, 0x1F, 0x1F, 0x1F,\n0x1F, 0x1F, 0x3E, 0x3E, 0x1E, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,\n0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x1E, 0x3E, 0x3E, 0x1F, 0x1F,\n0x1F, 0x1F, 0x1F, 0x0F, 0x0F, 0x0F, 0x07, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n};\n\nconst unsigned char MumbleLogo [] = {\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x40, 0x20, 0x20, 0x90, 0xD0, 0xC0, 0xC8, 0xE8, 0xE0, 0xE4, 0xC4, 0x04, 0x04, 0x04,\n0x04, 0x04, 0x04, 0x04, 0xC4, 0xE0, 0xE0, 0xE8, 0xC0, 0xC0, 0x90, 0x80, 0x20, 0x40, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x10, 0x04, 0x02, 0x01,\n0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x07, 0x01, 0x01, 0x01, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x03, 0x0F, 0xFF, 0xFF, 0xF8, 0x00, 0x00,\n0x01, 0x02, 0x04, 0x00, 0x20, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n0xC0, 0xC0, 0xE0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x1F, 0x1F, 0x3C, 0x38, 0x30,\n0x30, 0x30, 0x38, 0x1C, 0x1F, 0x0F, 0x03, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xE0, 0xC0,\n0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFE, 0xFF,\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFE, 0xFA, 0x02, 0x32, 0x22, 0x02, 0xFE, 0x02, 0x02,\n0xFE, 0xFE, 0xFE, 0x02, 0x02, 0x32, 0x32, 0x32, 0xFE, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n0xFF, 0xFF, 0xFE, 0xF8, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x30, 0xC0, 0x80, 0x1F, 0x7F, 0xFF,\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x3F, 0x7F, 0x40, 0x67, 0x66, 0x60, 0x79, 0x66, 0x40,\n0x47, 0x47, 0x47, 0x78, 0x40, 0x46, 0x47, 0x47, 0x7F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n0xFF, 0xFF, 0x3F, 0x8F, 0xC0, 0x30, 0x0E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08,\n0x11, 0x23, 0x63, 0x47, 0x87, 0x87, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x78, 0x78,\n0x78, 0x78, 0x78, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x90, 0x93, 0xCF, 0x47, 0x67, 0x23, 0x13,\n0x19, 0x0C, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x02, 0x02, 0x02, 0x02, 0x06, 0x06, 0x06,\n0x06, 0x06, 0x06, 0x02, 0x02, 0x02, 0x02, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n};\n\nconst unsigned char TeamspeakLogo [] = {\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x80, 0x80, 0xC0, 0xE0, 0xE0, 0xF0, 0xF0, 0xF0, 0x78, 0x78, 0x78, 0x38, 0x38, 0x38, 0x38,\n0x38, 0x38, 0x38, 0x38, 0x38, 0x78, 0x78, 0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0x80, 0x80, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xF4, 0xFE,\n0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F,\n0xFE, 0xF4, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xFC, 0xFF, 0x0F, 0x03, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x03, 0x1F, 0xFF, 0xFC, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,\n0x00, 0xF0, 0xF8, 0xFC, 0xFC, 0xF8, 0xF8, 0xF0, 0xE0, 0xC0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00,\n0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00,\n0x00, 0x01, 0x0F, 0x1F, 0x1F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x1E, 0x08, 0x00,\n0x00, 0x00, 0x18, 0x1C, 0x3E, 0x3E, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x1F, 0x03, 0x00,\n0x00, 0x00, 0xC0, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8,\n0xFC, 0x7F, 0x3F, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04,\n0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x03, 0x03, 0x03, 0x01,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n};\n\nconst unsigned char SpotifyLogo [] = {\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x80, 0xC0, 0xE0, 0xE0, 0xF0, 0xF0, 0xF8, 0xF8, 0xF8, 0xF8, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,\n0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF8, 0xF8, 0xF8, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0,\n0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF,\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n0xFF, 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1,\n0xC1, 0xC1, 0xE0, 0xE0, 0xE0, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,\n0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xC1, 0xC1, 0xC1, 0x81, 0x83, 0x83, 0x03, 0x07,\n0x07, 0x0F, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n0xE7, 0xC3, 0xC1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,\n0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xC1, 0xC1, 0xC3, 0x83, 0x83, 0x87, 0x07, 0x0F, 0x0F, 0x1F, 0x3F,\n0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n0xFF, 0xF7, 0xE3, 0xE3, 0xE1, 0xE1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1,\n0xF1, 0xF1, 0xE1, 0xE1, 0xE3, 0xE3, 0xC3, 0xC7, 0x87, 0x8F, 0x8F, 0x1F, 0xBF, 0xFE, 0xFE, 0xFF,\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F,\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\n0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n0x00, 0x01, 0x03, 0x03, 0x07, 0x07, 0x0F, 0x0F, 0x0F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,\n0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x0F, 0x0F, 0x0F, 0x07, 0x07, 0x03, 0x03, 0x01,\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n};\n\n\n// Initialize I2C buses using TCA9548A I2C Multiplexer\nvoid tcaselect(uint8_t i2c_bus) \n{\n    if (i2c_bus > 7) return;\n    Wire.beginTransmission(MUX_Address);\n    Wire.write(1 << i2c_bus);\n    Wire.endTransmission(); \n}\n\n// Einmallaufender Code\nvoid setup()\n{\n    Serial.begin(9600);\n\n    delay(10);\n    Serial.println('\\n');\n  \n     WiFi.begin(ssid, password);             // Connect to the network\n     Serial.print(\"Verbinde mit \");\n     Serial.print(ssid); \n     Serial.println(\" ...\");\n\n  int i = 0;\n  while (WiFi.status() != WL_CONNECTED) { // Wait for the Wi-Fi to connect\n    delay(1000);\n    Serial.print(++i); Serial.print(' ');\n  }\n\n  Serial.println('\\n');\n  Serial.println(\"Verbindung hergestellt!\");  \n  Serial.print(\"IP Addresse:\\t\");\n  Serial.println(WiFi.localIP());         // Send the IP address of the ESP8266 to the computer\n  \n}\n\n//Schleifencode\nvoid loop()\n{\n    if(Ping.ping(remote_ip)) \n    {\n      Serial.println(\"Monolith ONLINE!\");\n      Serial.println();\n      \n      bool ret = Ping.ping(remote_ip);\n      Serial.print (\"Status: \");\n      Serial.println(ret);\n    \n      int avg_time_ms = Ping.averageTime();\n      Serial.print(\"Ping: \");\n      Serial.print(avg_time_ms);\n      Serial.println(\"ms\");\n      Serial.println();\n\n\n    tcaselect(0);\n    ssd1306_128x64_i2c_init();\n    ssd1306_setFixedFont(ssd1306xled_font6x8);\n    ssd1306_clearScreen();\n    ssd1306_printFixed(45,  56, \"Chrome\", STYLE_NORMAL);\n    Serial.print(\"Chrome anzeigen\");\n    Serial.println(\"\");\n    ssd1306_drawBitmap(32, 0, 64, 56, ChromeLogo);\n    Serial.print(\"ChromeLogo anzeigen\");\n    Serial.println(\"\");\n    Serial.println(\"\");\n \n    tcaselect(0);\n    ssd1306_128x64_i2c_init();\n    ssd1306_setFixedFont(ssd1306xled_font6x8);\n    ssd1306_clearScreen();\n    ssd1306_printFixed(45,  56, \"Chrome\", STYLE_NORMAL);\n    Serial.print(\"Chrome anzeigen\");\n    Serial.println(\"\");\n    ssd1306_drawBitmap(32, 0, 64, 56, ChromeLogo);\n    Serial.print(\"ChromeLogo anzeigen\");\n    Serial.println(\"\");\n    Serial.println(\"\");\n  \n    tcaselect(2);\n    ssd1306_128x64_i2c_init();\n    ssd1306_setFixedFont(ssd1306xled_font6x8);\n    ssd1306_clearScreen();\n    ssd1306_printFixed(38,  56, \"Teamspeak\", STYLE_NORMAL);\n    Serial.print(\"Teamspeak anzeigen\");\n    Serial.println(\"\");\n    ssd1306_drawBitmap(32, 0, 64, 56, TeamspeakLogo);\n    Serial.print(\"TeamspeakLogo anzeigen\");\n    Serial.println(\"\");\n    Serial.println(\"\");\n\n    tcaselect(3);\n    ssd1306_128x64_i2c_init();\n    ssd1306_setFixedFont(ssd1306xled_font6x8);\n    ssd1306_clearScreen();\n    ssd1306_printFixed(45,  56, \"Mumble\", STYLE_NORMAL);\n    Serial.print(\"Mumble anzeigen\");\n    Serial.println(\"\");\n    ssd1306_drawBitmap(32, 0, 64, 56, MumbleLogo);\n    Serial.print(\"MumbleLogo anzeigen\");\n    Serial.println(\"\");\n    Serial.println(\"\");\n\n    tcaselect(4);\n    ssd1306_128x64_i2c_init();\n    ssd1306_setFixedFont(ssd1306xled_font6x8);\n    ssd1306_clearScreen();\n    ssd1306_printFixed(42,  56, \"Discord\", STYLE_NORMAL);\n    Serial.print(\"Discord anzeigen\");\n    Serial.println(\"\");\n    ssd1306_drawBitmap(32, 0, 64, 56, DiscordLogo);\n    Serial.print(\"DiscordLogo anzeigen\");\n    Serial.println(\"\");\n    Serial.println(\"\");\n\n    tcaselect(6);\n    ssd1306_128x64_i2c_init();\n    ssd1306_setFixedFont(ssd1306xled_font6x8);\n    ssd1306_clearScreen();\n    ssd1306_printFixed(42,  56, \"Spotify\", STYLE_NORMAL);\n    Serial.print(\"Spotify anzeigen\");\n    Serial.println(\"\");\n    ssd1306_drawBitmap(32, 0, 64, 56, SpotifyLogo);\n    Serial.print(\"SpotifyLogo anzeigen\");\n    Serial.println(\"\");\n    Serial.println(\"\");   \n\n    tcaselect(7);\n    ssd1306_128x64_i2c_init();\n    ssd1306_setFixedFont(ssd1306xled_font6x8);\n    ssd1306_clearScreen();\n    ssd1306_printFixed(23,  56, \"Master Volume\", STYLE_NORMAL);\n    Serial.print(\"Master Volume anzeigen\");\n    Serial.println(\"\");\n    ssd1306_drawBitmap(32, 0, 64, 56, WinLogo);\n    Serial.print(\"WinLogo anzeigen\");\n    Serial.println(\"\");\n    Serial.println(\"----------------\");\n\n    while(Ping.ping(remote_ip))\n        {\n        Serial.println(\"Warteschleife\");\n        delay (60000);\n        }\n\n    } \n\n    else \n\n    {\n        Serial.println(\"Monolith nicht ONLINE\");\n        Serial.println(\"Clearscreen\");\n        Serial.println();\n        tcaselect(0);\n        ssd1306_clearScreen();\n        tcaselect(1);\n        ssd1306_clearScreen();\n        tcaselect(2);\n        ssd1306_clearScreen();\n        tcaselect(3);\n        ssd1306_clearScreen();\n        tcaselect(4);\n        ssd1306_clearScreen();\n        tcaselect(5);\n        ssd1306_clearScreen();\n        tcaselect(6);\n        ssd1306_clearScreen();\n        tcaselect(7);\n        ssd1306_clearScreen();\n       \n    }\n\n  Serial.println(\"Verbindung unterbrochen\");\n  Serial.println(\"Clearscreen\");\n  Serial.println();\n  tcaselect(0);\n  ssd1306_clearScreen();\n  tcaselect(1);\n  ssd1306_clearScreen();\n  tcaselect(2);\n  ssd1306_clearScreen();\n  tcaselect(3);\n  ssd1306_clearScreen();\n  tcaselect(4);\n  ssd1306_clearScreen();\n  tcaselect(5);\n  ssd1306_clearScreen();\n  tcaselect(6);\n  ssd1306_clearScreen();\n  tcaselect(7);\n  ssd1306_clearScreen();\n  delay(5000);\n\n}\n"
  },
  {
    "path": "NK2Tray_Display/NK2Tray_DisplayFW_V2/NK2Tray_DisplayFW_V2.ino",
    "content": "// Display Firmware V2, made by piLo, tweaked by ZeeuwsGamertje\r\n// I2C Adressen:\r\n// Oled: 0x78\r\n// Multi:0x70\r\n\r\n// Directive for Serial Debugging\r\n//#define VERBOSE\r\n\r\n#include \"Wire.h\"               // Wire.h for I2c\r\n#include <ssd1306.h>            // 128x64 Display Ansteuerung, https://github.com/lexus2k/ssd1306\r\n#include <ESP8266WiFi.h>        // Include the Wi-Fi library\r\n#include <ESP8266Ping.h>        // Include the Ping library, https://github.com/dancol90/ESP8266Ping\r\n#include <DNSServer.h>          // For WiFi Manager\r\n#include <ESP8266WebServer.h>   // For Settings from Webinterface\r\n#include <WiFiManager.h>        // WiFiManager for AP and Client related Stuff\r\n#include <ArduinoOTA.h>         // For flashing over the Air\r\n#include <EEPROM.h>             // EEPROM Stuff\r\n#include \"logos.h\"\r\n\r\n#define MUX_Address 0x70        // TCA9548A Multiplexer Adresse\r\n\r\nESP8266WebServer webServer(80); // Init Webserver\r\n\r\nWiFiManager wifiManager;  // Init WiFiManager\r\n    \r\nIPAddress remote_ip(192, 168, 178, 69);       // Default value for Remote Host\r\nbool rem_host_online;                         // Online Status Remote Host\r\nunsigned long previousMillis = 0;             // For periodically Checking Host\r\nlong interval = 10000;                  // default value for checking host in s\r\n  \r\nbool always_on = true;                        // Default value for Always On mode\r\n\r\nbool refresh_displays = false;                // Flag for refreshing displays\r\n\r\nString local_ip;                              // String for esp8266 IP\r\n\r\nString MAC_address;                           // String for MAC-Address\r\nuint8_t MAC_array[6];                         // Char Array for MAC Adress\r\n\r\nchar chartmp[50];                             // CharTemp for converting Strings to CharArrays\r\n\r\nint display[] = { 0,0,0,0,0,0,0,0};           // Which Disp show what - default value\r\nString icons[] = { \"Chrome\", \"Discord\", \"Edge\", \"Empty\", \"Firefox\", \"Focus\", \"Gaming\", \"Master\", \"Mic\", \"Miscellaneous\", \"Mumble\", \"OperaGX\", \"Plex\", \"Safari\", \"Spotify\", \"System Sounds\", \"Teams\", \"Teamspeak\", \"Unassigned\", \"World of Warcraft\", \"YT-Music\" }; //Possible Values for Icons\r\n\r\n// Function for initializing I2C buses using TCA9548A I2C Multiplexer\r\nvoid tcaselect(uint8_t i2c_bus) \r\n{\r\n    if (i2c_bus > 7) return;\r\n    Wire.beginTransmission(MUX_Address);\r\n    Wire.write(1 << i2c_bus);\r\n    Wire.endTransmission(); \r\n}\r\n\r\n// Function to set specified display to icon\r\nvoid set_display(int display, int icon)\r\n{\r\n      tcaselect(display);\r\n      switch (icon) {\r\n        case 0: \r\n          ssd1306_printFixed(45,  56, \"Chrome\", STYLE_NORMAL);\r\n          ssd1306_drawBitmap(32, 0, 64, 56, chromeLogo);\r\n          break;\r\n        case 1:\r\n          ssd1306_printFixed(42,  56, \"Discord\", STYLE_NORMAL);\r\n          ssd1306_drawBitmap(32, 0, 64, 56, discordLogo);\r\n          break;\r\n        case 2:\r\n          ssd1306_printFixed(50,  56, \"Edge\", STYLE_NORMAL);\r\n          ssd1306_drawBitmap(32, 0, 64, 56, edgeLogo);\r\n          break;\r\n        case 3:\r\n          ssd1306_printFixed(62,  56, \"\", STYLE_NORMAL);\r\n          ssd1306_drawBitmap(32, 0, 64, 56, noLogo);\r\n          break;\r\n        case 4:\r\n          ssd1306_printFixed(42,  56, \"Firefox\", STYLE_NORMAL);\r\n          ssd1306_drawBitmap(32, 0, 64, 56, firefoxLogo);\r\n          break;\r\n        case 5:\r\n          ssd1306_printFixed(49,  56, \"Focus\", STYLE_NORMAL);\r\n          ssd1306_drawBitmap(32, 0, 64, 56, focusLogo);\r\n          break;\r\n        case 6:\r\n          ssd1306_printFixed(45,  56, \"Gaming\", STYLE_NORMAL);\r\n          ssd1306_drawBitmap(32, 0, 64, 56, gamingLogo);\r\n          break;\r\n        case 7:\r\n          ssd1306_printFixed(45,  56, \"Master\", STYLE_NORMAL);\r\n          ssd1306_drawBitmap(32, 0, 64, 56, masterLogo);\r\n          break;\r\n        case 8:\r\n          ssd1306_printFixed(54,  56, \"Mic\", STYLE_NORMAL);\r\n          ssd1306_drawBitmap(32, 0, 64, 56, micLogo);\r\n          break;\r\n        case 9:\r\n          ssd1306_printFixed(26,  56, \"Miscellaneous\", STYLE_NORMAL);\r\n          ssd1306_drawBitmap(32, 0, 64, 56, miscLogo);\r\n          break;\r\n        case 10:\r\n          ssd1306_printFixed(45,  56, \"Mumble\", STYLE_NORMAL);\r\n          ssd1306_drawBitmap(32, 0, 64, 56, mumbleLogo);\r\n          break;\r\n        case 11:\r\n          ssd1306_printFixed(42,  56, \"OperaGX\", STYLE_NORMAL);\r\n          ssd1306_drawBitmap(32, 0, 64, 56, operagxLogo);\r\n          break;\r\n        case 12:\r\n          ssd1306_printFixed(50,  56, \"Plex\", STYLE_NORMAL);\r\n          ssd1306_drawBitmap(32, 0, 64, 56, plexLogo);\r\n          break;\r\n        case 13:\r\n          ssd1306_printFixed(45,  56, \"Safari\", STYLE_NORMAL);\r\n          ssd1306_drawBitmap(32, 0, 64, 56, safariLogo);\r\n          break;\r\n        case 14:\r\n          ssd1306_printFixed(42,  56, \"Spotify\", STYLE_NORMAL);\r\n          ssd1306_drawBitmap(32, 0, 64, 56, spotifyLogo);\r\n          break;        \r\n        case 15:\r\n          ssd1306_printFixed(23,  56, \"System Sounds\", STYLE_NORMAL);\r\n          ssd1306_drawBitmap(32, 0, 64, 56, windowsLogo);\r\n          break;\r\n        case 16:\r\n          ssd1306_printFixed(49,  56, \"Teams\", STYLE_NORMAL);\r\n          ssd1306_drawBitmap(32, 0, 64, 56, teamsLogo);\r\n          break;\r\n        case 17:\r\n          ssd1306_printFixed(38,  56, \"Teamspeak\", STYLE_NORMAL);\r\n          ssd1306_drawBitmap(32, 0, 64, 56, teamspeakLogo);\r\n          break;\r\n        case 18:\r\n          ssd1306_printFixed(36,  56, \"Unassigned\", STYLE_NORMAL);\r\n          ssd1306_drawBitmap(32, 0, 64, 56, unassignedLogo);\r\n          break;\r\n        case 19:\r\n          ssd1306_printFixed(54,  56, \"WoW\", STYLE_NORMAL);\r\n          ssd1306_drawBitmap(32, 0, 64, 56, wowLogo);\r\n          break;\r\n        case 20:\r\n          ssd1306_printFixed(40,  56, \"YT-Music\", STYLE_NORMAL);\r\n          ssd1306_drawBitmap(32, 0, 64, 56, ytmusicLogo);\r\n          break;\r\n              \r\n      }\r\n}\r\n\r\n// function to clear all screens\r\nvoid clear_screens()\r\n{\r\n  for (int i = 0; i <= 7; i++)\r\n  {\r\n    tcaselect(i);\r\n    ssd1306_clearScreen();\r\n  }\r\n}\r\n\r\n// function for checking remote host\r\nbool check_remote_host()\r\n{\r\n  unsigned long currentMillis = millis();\r\n  if (currentMillis - previousMillis >= interval)\r\n  {\r\n    previousMillis = currentMillis; \r\n    if (Ping.ping(remote_ip)) {\r\n      #ifdef VERBOSE\r\n        Serial.println(\"Host ONLINE!\");\r\n        Serial.println();\r\n        int avg_time_ms = Ping.averageTime();\r\n        Serial.print(\"Ping: \");\r\n        Serial.print(avg_time_ms);\r\n        Serial.println(\"ms\");\r\n        Serial.println();\r\n      #endif\r\n      rem_host_online = true;\r\n    } else {\r\n      #ifdef VERBOSE\r\n        Serial.println(\"Host offline!\");\r\n      #endif\r\n      rem_host_online=false;\r\n    }\r\n  }\r\n}\r\n\r\n// function for getting mac address\r\nvoid getMac() {\r\n  char MAC_char[30] = \"\";\r\n  \r\n  WiFi.macAddress(MAC_array);\r\n  \r\n  // Format the MAC address into string\r\n  sprintf(MAC_char, \"%02X\", MAC_array[0]);\r\n  for (int i = 1; i < 6; ++i) {\r\n    sprintf(MAC_char, \"%s : %02X\", MAC_char, MAC_array[i]);\r\n  }\r\n  MAC_address = String(MAC_char);\r\n}\r\n\r\n// Setup Code\r\nvoid setup()\r\n{\r\n    EEPROM.begin(512);\r\n    #ifdef VERBOSE\r\n      Serial.begin(9600);\r\n      Serial.println(\"Setup Started\");\r\n    #endif\r\n      \r\n    wifiManager.autoConnect(\"NK2Tray_Display\"); \r\n\r\n    local_ip = WiFi.localIP().toString();\r\n    local_ip.toCharArray(chartmp, 50);\r\n\r\n    getMac();\r\n    \r\n    startWebServer();\r\n\r\n    ArduinoOTA.setHostname(\"NK2Tray-Display\");\r\n    ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {\r\n    for ( int i = 0; i <= 7; i++)\r\n    {\r\n      tcaselect(i);\r\n      ssd1306_drawBitmap(32, 0, 64, 64, firmwareLogo);\r\n      ssd1306_printFixed(14, 56, \"updating firmware\", STYLE_NORMAL);\r\n      #ifdef VERBOSE\r\n        Serial.printf(\"Progress: %u%%\\r\", (progress / (total / 100)));\r\n      #endif\r\n    }\r\n    });\r\n    ArduinoOTA.begin();\r\n\r\n    loadSettings();\r\n\r\n  for (int i = 0; i <= 7; i++)\r\n  {\r\n    tcaselect(i);\r\n    delay(10);\r\n    ssd1306_128x64_i2c_init();\r\n    delay(10);\r\n    ssd1306_setFixedFont(ssd1306xled_font6x8);\r\n  }\r\n\r\n  clear_screens();\r\n  \r\n  tcaselect(0);  \r\n  delay(10);\r\n  ssd1306_128x64_i2c_init();\r\n  delay(10);\r\n  ssd1306_drawBitmap(0, 0, 128, 64, piloLogo);\r\n  tcaselect(1);\r\n  ssd1306_printFixed(34, 32, \"Booting...\", STYLE_NORMAL);\r\n  tcaselect(2);\r\n  ssd1306_printFixed(54, 32, \"IP: \", STYLE_NORMAL);\r\n  tcaselect(3);\r\n  ssd1306_printFixed(20, 32, chartmp, STYLE_NORMAL);\r\n  tcaselect(4);\r\n  ssd1306_printFixed(20, 32, \"NK2Tray-Display\", STYLE_NORMAL);  \r\n  tcaselect(5);\r\n  ssd1306_printFixed(15, 32, \"Firmware by piLo\", STYLE_NORMAL);\r\n  tcaselect(6);\r\n  ssd1306_printFixed(0, 30, \"Tweaked by\", STYLE_NORMAL);\r\n  ssd1306_printFixed(0, 40, \"ZeeuwsGamertje\", STYLE_NORMAL);\r\n  tcaselect(7);\r\n  ssd1306_drawBitmap(0, 0, 128, 64, zeeuwsLogo);\r\n  \r\n  delay(10000);\r\n\r\n  clear_screens();\r\n\r\n  refresh_displays = true;\r\n}\r\n\r\n//Schleifencode\r\nvoid loop()\r\n{\r\n    if(always_on == true) {\r\n      if(refresh_displays)\r\n      {\r\n        clear_screens();\r\n        for (int i = 0; i <= 7; i++)\r\n        {\r\n          set_display(i, display[i]);\r\n        }\r\n        refresh_displays = false;\r\n      }\r\n    \r\n    } else if (rem_host_online) {\r\n      if (refresh_displays)\r\n      {  \r\n        clear_screens();\r\n        for (int i = 0; i <= 7; i++)\r\n        {\r\n          set_display(i, display[i]);\r\n        }\r\n        refresh_displays = false;      \r\n      }\r\n    } else {\r\n        clear_screens();\r\n        refresh_displays=true;\r\n    }\r\n    \r\n    if(!always_on)\r\n    {\r\n      check_remote_host();\r\n    }\r\n    webServer.handleClient();\r\n    ArduinoOTA.handle();\r\n}\r\n"
  },
  {
    "path": "NK2Tray_Display/NK2Tray_DisplayFW_V2/eeprom.ino",
    "content": "// function to save our variables into EEPROM\r\n// Writes OK to 500 & 501 - use this to verify a write\r\nbool saveSettings() {\r\n  \r\n  #ifdef VERBOSE\r\n    Serial.print(\"Saving Settings... \");\r\n  #endif\r\n\r\n  // Wipe our OK and check\r\n  EEPROM.write(500, '\\0');\r\n  EEPROM.write(501, '\\0');\r\n  EEPROM.commit();\r\n  if(EEPROM.read(500) != '\\0'|| EEPROM.read(501) != '\\0') {\r\n      #ifdef VERBOSE\r\n        Serial.println(\"fail!\");  \r\n      #endif  \r\n    return false;\r\n  }\r\n  \r\n  delay(100);\r\n  \r\n  EEPROM.write(100, remote_ip[0]);\r\n  EEPROM.write(101, remote_ip[1]);\r\n  EEPROM.write(102, remote_ip[2]);\r\n  EEPROM.write(103, remote_ip[3]);\r\n \r\n  if (always_on) {\r\n    EEPROM.write(104, 1);\r\n  } else {\r\n    EEPROM.write(104, 0);\r\n  }\r\n  \r\n  for (int i = 0; i <= 7; i++)\r\n  {\r\n    EEPROM.write(105+i, display[i]);\r\n  }\r\n\r\n  EEPROM.write(115, interval/1000);\r\n    \r\n  EEPROM.write(500, 'O');\r\n  EEPROM.write(501, 'K');\r\n\r\n  delay(100);\r\n  \r\n  EEPROM.commit();\r\n  \r\n  delay (100);\r\n\r\n  // Verify our OK was written & return false if not\r\n  if(EEPROM.read(500) != 'O' || EEPROM.read(501) != 'K') {\r\n    #ifdef VERBOSE\r\n      Serial.println(\"fail!\");\r\n    #endif\r\n    return false;\r\n  }\r\n  #ifdef VERBOSE\r\n    Serial.println(\"success!\");\r\n  #endif\r\n\r\n  // Return true if all went well\r\n  return true;\r\n}\r\n\r\n\r\n\r\n// Function to load our settings from EEPROM to our variables.\r\nbool loadSettings() {\r\n  #ifdef VERBOSE\r\n    Serial.print(\"Loading Settings... \");\r\n  #endif\r\n  \r\n\r\n// Check if we have previous saves.  If not, return false\r\n  if(EEPROM.read(500) != 'O' || EEPROM.read(501) != 'K') {\r\n    #ifdef VERBOSE\r\n      Serial.println(\"No previous saves.\");\r\n    #endif    \r\n    return false;\r\n  }\r\n\r\n   remote_ip[0] = EEPROM.read(100);\r\n   remote_ip[1] = EEPROM.read(101);\r\n   remote_ip[2] = EEPROM.read(102);\r\n   remote_ip[3] = EEPROM.read(103);\r\n\r\n   if (EEPROM.read(104) == 0)\r\n   {\r\n      always_on = false;\r\n   } else {\r\n      always_on = true;\r\n   }\r\n    \r\n   for (int i = 0; i <= 7; i++)\r\n   {\r\n     display[i] = EEPROM.read(105+i);\r\n   }\r\n\r\n   interval = EEPROM.read(115) * 1000;\r\n   \r\n   #ifdef VERBOSE\r\n     Serial.println(\"success!\");\r\n   #endif\r\n   // Return\r\n   return true;\r\n}\r\n"
  },
  {
    "path": "NK2Tray_Display/NK2Tray_DisplayFW_V2/logos.h",
    "content": "// Anzuzeigende Bilder:\r\n\r\n// Windows Logo\r\nconst unsigned char windowsLogo [] = {\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x80, 0xC0, 0xC0, 0xE0, 0xE0, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0xE0,\r\n0xC0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xF8,\r\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\r\n0xFF, 0x1F, 0x03, 0x00, 0x00, 0x00, 0xF0, 0xFC, 0xF8, 0xF8, 0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0xE0,\r\n0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xF0, 0xF0, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x38, 0x3F, 0x1F,\r\n0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x3F, 0x3F, 0x7F, 0x7F, 0xFF, 0x0F,\r\n0x03, 0x00, 0x00, 0x80, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\r\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xF0, 0xF8, 0xF8, 0xFC, 0xFC,\r\n0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF0, 0x70, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x07, 0x0F, 0x0F, 0x0F, 0x1F, 0x1F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,\r\n0x3F, 0x1F, 0x1F, 0x0F, 0x0F, 0x0F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\r\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x0F, 0x00, 0x00, 0x00, 0xD0,\r\n0xFC, 0xFF, 0xFF, 0xFE, 0xFE, 0xFC, 0xFC, 0xFC, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xFC,\r\n0xFC, 0xFC, 0xFC, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0F, 0x0F, 0x07, 0x07, 0x07, 0x07, 0x03, 0x03, 0x03,\r\n0x03, 0x07, 0x07, 0x07, 0x0F, 0x0F, 0x0F, 0x1F, 0x3F, 0x07, 0x00, 0x00, 0x00, 0xF0, 0xFE, 0xFF,\r\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\r\n0x3F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03,\r\n0x03, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x03, 0x01, 0x01,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r\n};\r\n\r\n// Chrome Logo\r\nconst unsigned char chromeLogo [] = {\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x80, 0x80, 0xC0, 0xE0, 0xE0, 0xF0, 0xF0, 0xF0, 0xF8, 0xF8, 0xF8, 0xF8, 0xFC, 0xFC, 0xFC,\r\n0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF8, 0xF8, 0xF8, 0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0x80,\r\n0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x3C, 0xFE,\r\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x7F,\r\n0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,\r\n0x7F, 0x7F, 0x7E, 0x7C, 0x78, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xF8, 0xFF, 0xFF, 0xFF, 0xFE, 0xF8, 0xE0,\r\n0x81, 0x07, 0x1F, 0x3F, 0xFF, 0x7F, 0x1F, 0x0F, 0x83, 0xC1, 0xF1, 0xF0, 0xF8, 0xFC, 0xFC, 0xFC,\r\n0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF0, 0xF0, 0xC0, 0x80, 0x04, 0x1C, 0x7C, 0xFC, 0xFC, 0xFC,\r\n0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\r\n0xFF, 0xFF, 0xFC, 0xF0, 0xC0, 0x80, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\r\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF,\r\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\r\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFC, 0xF0, 0xF0, 0xE3, 0xC3, 0xC7, 0x8F, 0x8F, 0x8F,\r\n0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x07, 0x03, 0x03, 0xC0, 0xE0, 0xF8, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,\r\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x0F, 0x1F,\r\n0x3F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\r\n0x7F, 0x1F, 0x07, 0x81, 0xE0, 0xF8, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,\r\n0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x03, 0x03, 0x07, 0x07, 0x07, 0x0F, 0x0F, 0x03, 0x00,\r\n0x00, 0x0C, 0x0E, 0x0F, 0x0F, 0x0F, 0x07, 0x07, 0x07, 0x03, 0x03, 0x03, 0x01, 0x01, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r\n};\r\n\r\n// Discord Logo\r\nconst unsigned char discordLogo [] = {\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xE0, 0xF0,\r\n0x70, 0x70, 0x38, 0x38, 0x18, 0x18, 0x18, 0x9C, 0x8C, 0x88, 0x80, 0x80, 0xC0, 0xC0, 0xC0, 0xC0,\r\n0xC0, 0xC0, 0xC0, 0xC0, 0x80, 0x80, 0x88, 0x8C, 0x9C, 0x18, 0x18, 0x18, 0x38, 0x38, 0x70, 0x70,\r\n0xF0, 0xE0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xF8, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFC,\r\n0xFC, 0xFC, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\r\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFC, 0xFC,\r\n0xFC, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xF8, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x80, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\r\n0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x3F, 0x1F, 0x3F, 0x3F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\r\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x3F, 0x1F, 0x3F, 0x3F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF,\r\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x80, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\r\n0xFF, 0xFF, 0xFF, 0xF1, 0xC0, 0x80, 0x80, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF,\r\n0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x80, 0x80, 0xC0, 0xF1, 0xFF, 0xFF, 0xFF,\r\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xC7, 0x8F, 0x8F,\r\n0x1F, 0x1F, 0x3F, 0x3F, 0x7F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\r\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x7F, 0x3F, 0x3F, 0x1F, 0x1F,\r\n0x8F, 0x8F, 0xC7, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x07, 0x0F, 0x0F, 0x0F, 0x1F, 0x1F, 0x1F,\r\n0x1F, 0x1F, 0x3E, 0x3E, 0x1E, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,\r\n0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x1E, 0x3E, 0x3E, 0x1F, 0x1F,\r\n0x1F, 0x1F, 0x1F, 0x0F, 0x0F, 0x0F, 0x07, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r\n};\r\n\r\n// Mumble Logo\r\nconst unsigned char mumbleLogo [] = {\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x40, 0x20, 0x20, 0x90, 0xD0, 0xC0, 0xC8, 0xE8, 0xE0, 0xE4, 0xC4, 0x04, 0x04, 0x04,\r\n0x04, 0x04, 0x04, 0x04, 0xC4, 0xE0, 0xE0, 0xE8, 0xC0, 0xC0, 0x90, 0x80, 0x20, 0x40, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x10, 0x04, 0x02, 0x01,\r\n0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x07, 0x01, 0x01, 0x01, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x03, 0x0F, 0xFF, 0xFF, 0xF8, 0x00, 0x00,\r\n0x01, 0x02, 0x04, 0x00, 0x20, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\r\n0xC0, 0xC0, 0xE0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x1F, 0x1F, 0x3C, 0x38, 0x30,\r\n0x30, 0x30, 0x38, 0x1C, 0x1F, 0x0F, 0x03, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xE0, 0xC0,\r\n0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFE, 0xFF,\r\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFE, 0xFA, 0x02, 0x32, 0x22, 0x02, 0xFE, 0x02, 0x02,\r\n0xFE, 0xFE, 0xFE, 0x02, 0x02, 0x32, 0x32, 0x32, 0xFE, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\r\n0xFF, 0xFF, 0xFE, 0xF8, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x30, 0xC0, 0x80, 0x1F, 0x7F, 0xFF,\r\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x3F, 0x7F, 0x40, 0x67, 0x66, 0x60, 0x79, 0x66, 0x40,\r\n0x47, 0x47, 0x47, 0x78, 0x40, 0x46, 0x47, 0x47, 0x7F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\r\n0xFF, 0xFF, 0x3F, 0x8F, 0xC0, 0x30, 0x0E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08,\r\n0x11, 0x23, 0x63, 0x47, 0x87, 0x87, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x78, 0x78,\r\n0x78, 0x78, 0x78, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x90, 0x93, 0xCF, 0x47, 0x67, 0x23, 0x13,\r\n0x19, 0x0C, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x02, 0x02, 0x02, 0x02, 0x06, 0x06, 0x06,\r\n0x06, 0x06, 0x06, 0x02, 0x02, 0x02, 0x02, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r\n};\r\n\r\n// Teamspeak Logo\r\nconst unsigned char teamspeakLogo [] = {\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x80, 0x80, 0xC0, 0xE0, 0xE0, 0xF0, 0xF0, 0xF0, 0x78, 0x78, 0x78, 0x38, 0x38, 0x38, 0x38,\r\n0x38, 0x38, 0x38, 0x38, 0x38, 0x78, 0x78, 0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0x80, 0x80, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xF4, 0xFE,\r\n0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F,\r\n0xFE, 0xF4, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xFC, 0xFF, 0x0F, 0x03, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x03, 0x1F, 0xFF, 0xFC, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,\r\n0x00, 0xF0, 0xF8, 0xFC, 0xFC, 0xF8, 0xF8, 0xF0, 0xE0, 0xC0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00,\r\n0x00, 0x01, 0x0F, 0x1F, 0x1F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x1E, 0x08, 0x00,\r\n0x00, 0x00, 0x18, 0x1C, 0x3E, 0x3E, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x1F, 0x03, 0x00,\r\n0x00, 0x00, 0xC0, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8,\r\n0xFC, 0x7F, 0x3F, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04,\r\n0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x03, 0x03, 0x03, 0x01,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r\n};\r\n\r\n// Spotify Logo\r\nconst unsigned char spotifyLogo [] = {\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x80, 0xC0, 0xE0, 0xE0, 0xF0, 0xF0, 0xF8, 0xF8, 0xF8, 0xF8, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,\r\n0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF8, 0xF8, 0xF8, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0,\r\n0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF,\r\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,\r\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\r\n0xFF, 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1,\r\n0xC1, 0xC1, 0xE0, 0xE0, 0xE0, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,\r\n0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xC1, 0xC1, 0xC1, 0x81, 0x83, 0x83, 0x03, 0x07,\r\n0x07, 0x0F, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\r\n0xE7, 0xC3, 0xC1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,\r\n0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xC1, 0xC1, 0xC3, 0x83, 0x83, 0x87, 0x07, 0x0F, 0x0F, 0x1F, 0x3F,\r\n0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\r\n0xFF, 0xF7, 0xE3, 0xE3, 0xE1, 0xE1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1,\r\n0xF1, 0xF1, 0xE1, 0xE1, 0xE3, 0xE3, 0xC3, 0xC7, 0x87, 0x8F, 0x8F, 0x1F, 0xBF, 0xFE, 0xFE, 0xFF,\r\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F,\r\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\r\n0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,\r\n0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r\n0x00, 0x01, 0x03, 0x03, 0x07, 0x07, 0x0F, 0x0F, 0x0F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,\r\n0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x0F, 0x0F, 0x0F, 0x07, 0x07, 0x03, 0x03, 0x01,\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r\n};\r\n\r\n// Plex Logo\r\nconst unsigned char plexLogo [] = {\r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x3f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, \r\n0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, \r\n0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, \r\n0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x3f, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, \r\n0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x0f, 0x1f, 0x7f, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xfc, 0xf8, 0xe0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xf0, 0xf8, 0xfe, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0x3f, 0x1f, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, \r\n0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xfc, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, \r\n0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, \r\n0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, \r\n0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff  \r\n};\r\n\r\n// Focus Logo\r\nconst unsigned char focusLogo [] = {\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, \r\n0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0xc0, 0xe0, 0xe0, 0xf0, 0xf8, 0x78, 0x7c, 0x3c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, \r\n0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x3c, 0x3c, 0x7c, 0xf8, 0xf0, 0xf0, 0xe0, 0xc0, 0x80, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xfc, 0xfe, \r\n0xff, 0x1f, 0x0f, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0f, \r\n0x0f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x1f, 0xff, \r\n0xfe, 0xfc, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, \r\n0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, \r\n0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3f, 0x7f, \r\n0xff, 0xf8, 0xf0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xf0, \r\n0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf8, 0xff, \r\n0x7f, 0x3f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x01, 0x03, 0x07, 0x0f, 0x0f, 0x1f, 0x1e, 0x3c, 0x3c, 0x78, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, \r\n0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x78, 0x3c, 0x3c, 0x3e, 0x1f, 0x0f, 0x0f, 0x07, 0x03, 0x01, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, \r\n0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r\n};\r\n\r\n// Microphone Logo\r\nconst unsigned char micLogo [] = {\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xfc, 0xfc, 0xfe, 0xff, 0xff, \r\n0xff, 0xff, 0xfe, 0xfe, 0xfc, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x1f, 0x7f, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0f, 0x1f, 0x3f, 0x3e, 0x7c, 0x78, 0x78, 0x79, 0xf1, 0xf1, \r\n0xf1, 0xf1, 0xf1, 0x79, 0x78, 0x7c, 0x3c, 0x3f, 0x1f, 0x0f, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, \r\n0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r\n};\r\n\r\n// Speaker Logo\r\nconst unsigned char masterLogo [] = {\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xc0, 0xe0, 0xe0, 0xf0, \r\n0xf8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x80, 0xc0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0xc0, 0xc0, \r\n0xe0, 0xf0, 0xf0, 0xf8, 0xf8, 0xfc, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xe0, 0xf0, 0xf0, \r\n0xe0, 0x80, 0x03, 0x07, 0x1f, 0x3f, 0xff, 0xfe, 0xfc, 0xf0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0xf8, 0xfc, 0xfc, 0xf0, 0xc0, 0x00, 0x01, 0x07, 0x7f, \r\n0xff, 0xff, 0xfe, 0xf8, 0x00, 0x00, 0x01, 0x0f, 0xff, 0xff, 0xff, 0xfe, 0xc0, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x30, 0x7f, 0xff, 0xff, 0x3f, 0x0f, 0x00, 0x00, 0x80, 0xf8, \r\n0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x00, 0x00, 0x07, 0x0f, 0x0f, \r\n0x1f, 0x1f, 0x3f, 0x7f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1f, 0x3f, 0x3f, \r\n0x0f, 0x07, 0x01, 0x80, 0xe0, 0xf8, 0xfe, 0xff, 0xff, 0x3f, 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07, 0x07, 0x0f, 0x1f, 0x1f, 0x3f, \r\n0x3f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x03, 0x07, 0x0f, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r\n};\r\n\r\n// Misc Logo\r\nconst unsigned char miscLogo [] = {\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0x80, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xc0, 0xe0, 0xe0, \r\n0xe0, 0xe0, 0xc0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x80, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x3c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x03, 0x01, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x07, 0x07, \r\n0x07, 0x07, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x01, 0x03, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 \r\n};\r\n\r\n// Gaming Logo\r\nconst unsigned char gamingLogo [] = {\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xfe, 0xfe, \r\n0xfe, 0xfe, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x80, 0xe0, 0xf0, 0xf8, 0x78, 0x3c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, \r\n0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1f, 0x1f, 0x1f, 0x1e, 0x1c, 0x1c, 0x1c, 0x1c, \r\n0x1c, 0x1c, 0x1c, 0x1c, 0x1e, 0x1f, 0x1f, 0x1f, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, \r\n0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x3c, 0x7c, 0xf8, 0xf0, 0xe0, 0x80, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, \r\n0xc0, 0xfc, 0xfc, 0xfc, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x18, 0x3c, 0x18, 0x00, \r\n0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, \r\n0x03, 0x7f, 0x7f, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x03, 0x03, 0x01, 0x00, 0x30, 0x70, 0x30, 0x00, \r\n0x00, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x03, 0x0f, 0x1f, 0x3f, 0x3c, 0x78, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, \r\n0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, \r\n0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, \r\n0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x78, 0x78, 0x3f, 0x1f, 0x0f, 0x03, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  \r\n};\r\n\r\n// pilo logo\r\nconst unsigned char piloLogo [] = {\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x70, 0x78, 0x3c, 0x3c, 0xfe, 0xfe, 0xfe, 0xe0, 0x00, 0x01, 0x1f, 0xff, 0xff, 0xff, 0xe7, \r\n0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xfe, 0xf0, 0x00, 0x01, 0x1f, 0xff, 0xff, \r\n0xfe, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x60, 0xe0, 0xe0, 0xf0, 0xf0, 0xf3, 0xf3, 0xf9, 0xf9, 0xf8, 0xf8, 0xfc, 0xfc, \r\n0xfc, 0xfc, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0x1f, 0x01, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf1, 0x63, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0x7f, 0x07, 0x00, 0xe0, 0xc6, 0xc7, 0xc7, 0xc7, 0x8f, 0x8f, 0x8f, 0x9e, \r\n0x1e, 0x1e, 0x1e, 0x3c, 0x3c, 0x3c, 0x7f, 0x7f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x7c, 0xfc, 0xf0, 0xf0, 0xf8, 0x7c, 0x3e, \r\n0x1f, 0x0f, 0x87, 0xc3, 0xe1, 0xf0, 0xf8, 0xfc, 0x7e, 0x3e, 0x1e, 0x0c, 0x00, 0x01, 0x03, 0x07, \r\n0x0f, 0x1f, 0x3f, 0x07, 0x00, 0x00, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x07, 0x07, 0x07, 0x07, \r\n0x0f, 0xcf, 0xef, 0xfe, 0x7e, 0x3e, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x01, 0x00, 0x18, 0x3c, \r\n0x3e, 0x7f, 0x7f, 0xff, 0xe7, 0x63, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r\n};\r\n\r\n// firmware update logo\r\nconst unsigned char firmwareLogo [] = {\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xc0, \r\n0xe0, 0xf0, 0x70, 0x78, 0x38, 0x1c, 0x1c, 0x1c, 0x0e, 0x0e, 0x0e, 0x0e, 0x07, 0x07, 0x07, 0x07, \r\n0x07, 0x07, 0x07, 0x07, 0x0e, 0x0e, 0x0e, 0x0e, 0x1c, 0x1c, 0x3c, 0x38, 0x78, 0x70, 0xf0, 0xe0, \r\n0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xe0, 0xf0, 0xfc, 0x3e, 0x1f, 0x07, 0x03, 0x01, \r\n0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00, \r\n0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, \r\n0x03, 0x07, 0x0f, 0x1f, 0x3c, 0xf8, 0xf0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xfe, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0xf8, 0xfc, 0x0d, 0xcd, 0xec, 0xec, 0xec, 0xed, 0xec, 0xec, \r\n0xec, 0x0d, 0x0c, 0xf8, 0x00, 0x20, 0x30, 0x30, 0x30, 0x30, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x1f, 0xff, 0xfc, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x23, 0x23, 0x23, 0x23, 0x22, 0x00, 0x7f, 0xff, 0x80, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x1f, 0xdf, \r\n0xdf, 0xc0, 0xf8, 0x7b, 0x70, 0x70, 0x7c, 0x7c, 0xf0, 0xf0, 0xf8, 0xf8, 0xc0, 0xc0, 0xc0, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x7f, 0xff, 0xf0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xcc, \r\n0xff, 0xff, 0xff, 0xf0, 0xf8, 0xf0, 0xe0, 0xc1, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xdc, 0x0c, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xf8, 0xff, 0x3f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x0f, 0x1f, 0x3c, 0xf8, 0xf0, 0xe0, 0xc0, \r\n0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x07, 0x07, 0x03, 0x03, 0x0f, 0x0f, 0x07, 0x03, 0x07, 0x07, 0x04, 0x00, 0x00, 0x80, \r\n0xc0, 0xe0, 0xf0, 0x78, 0x3e, 0x1f, 0x0f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, \r\n0x07, 0x07, 0x0e, 0x1e, 0x1c, 0x1c, 0x38, 0x38, 0x38, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x60, \r\n0x60, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x38, 0x38, 0x38, 0x1c, 0x1c, 0x0e, 0x0f, 0x07, 0x07, \r\n0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  \r\n};\r\n\r\n// unassigned logo\r\nconst unsigned char unassignedLogo [] = {\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, \r\n0xe0, 0xf0, 0xf8, 0xf8, 0xfc, 0x7c, 0x7c, 0x3e, 0x3e, 0x3e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, \r\n0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1e, 0x3e, 0x3e, 0x3e, 0x7c, 0x7c, 0xfc, 0xf8, 0xf8, 0xf0, 0xe0, \r\n0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xe0, 0xf8, 0xfc, 0xfe, 0x7f, 0x3f, 0x1f, 0x07, \r\n0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf9, 0xff, 0xff, \r\n0x7f, 0x3f, 0x3f, 0x7f, 0xfe, 0xfc, 0xf8, 0xe0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x80, 0xf8, 0xff, 0xff, 0xff, 0x3f, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x3f, 0xff, 0xff, 0xff, 0xf8, 0x80, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, \r\n0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x01, 0x1f, 0xff, 0xff, 0xff, 0xfc, 0xe0, 0x80, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x80, 0xe0, 0xfc, 0xff, 0xff, 0xff, 0x1f, 0x01, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x1f, 0x3f, 0x7f, 0xfe, 0xfc, 0xfc, 0xfe, \r\n0xff, 0xff, 0x9f, 0x0f, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, \r\n0xe0, 0xf8, 0xfc, 0xfe, 0x7f, 0x3f, 0x1f, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, \r\n0x07, 0x0f, 0x1f, 0x1f, 0x3f, 0x3e, 0x3e, 0x7c, 0x7c, 0x7c, 0x78, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, \r\n0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0x78, 0x7c, 0x7c, 0x7c, 0x3e, 0x3e, 0x3f, 0x1f, 0x1f, 0x0f, 0x07, \r\n0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r\n};\r\n\r\n// teams logo\r\nconst unsigned char teamsLogo [] = {\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xc0, 0xe0, 0xe0, \r\n0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, \r\n0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0xf0, 0xfc, 0xfe, 0xfe, 0xfe, \r\n0xfe, 0xfe, 0xfe, 0xfe, 0xfc, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0x9f, 0x9f, 0x9f, 0x8f, 0x8f, 0x8f, 0x87, 0x83, 0x80, 0x80, 0x80, 0x80, 0x83, 0x87, 0x87, 0x87, \r\n0x87, 0x87, 0x87, 0x87, 0x83, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, \r\n0x01, 0x01, 0x01, 0x01, 0x01, 0x07, 0x1f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x3f, 0x1f, 0x03, 0x03, 0x03, \r\n0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x03, 0x07, 0x07, 0x07, \r\n0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r\n};\r\n\r\n// operaGX logo\r\nconst unsigned char operagxLogo [] = {\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xe0, \r\n0xf0, 0xf8, 0x78, 0x3c, 0x3c, 0x3e, 0x1e, 0x1e, 0x0f, 0x0f, 0x8f, 0xcf, 0xcf, 0xe7, 0xe7, 0xf7, \r\n0xf7, 0xf7, 0xff, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0xfc, 0xf8, 0xf8, 0xf0, 0xf0, \r\n0xe0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xf0, 0xfc, 0xfe, 0x7f, 0x1f, 0x0f, 0x03, 0x03, \r\n0x01, 0x00, 0x00, 0x80, 0xc0, 0xf0, 0xf8, 0xfe, 0x3e, 0x1f, 0x0f, 0x07, 0x03, 0x03, 0x01, 0x01, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0c, 0x1c, 0x38, 0xf0, 0xf0, 0xe0, 0xc0, 0x80, 0x01, 0x01, \r\n0x03, 0x07, 0x0f, 0x1f, 0x7e, 0xfe, 0xfc, 0xf0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0xe0, 0xfe, 0xff, 0xff, 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0xf0, 0xfe, 0xff, 0xff, 0x0f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x7f, 0xff, 0xfe, 0xf0, \r\n0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x1f, 0xff, 0xff, 0xfc, 0xe0, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0xff, 0xff, 0xff, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, \r\n0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x0f, 0x7f, 0xff, 0xff, 0xf8, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x0f, 0x7f, 0xff, 0xff, 0xf0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xe0, 0xfe, 0xff, 0x7f, 0x0f, \r\n0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xf8, 0xff, 0xff, 0x3f, 0x07, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0f, 0x3f, 0x7f, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, \r\n0x80, 0x00, 0x00, 0x01, 0x03, 0x0f, 0x1f, 0x3f, 0x7c, 0xfc, 0xf0, 0xe0, 0xc0, 0xc0, 0x80, 0x80, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x30, 0x38, 0x1c, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x80, 0x80, \r\n0xc0, 0xe0, 0xf0, 0xf8, 0x7e, 0x7f, 0x3f, 0x0f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x07, \r\n0x0f, 0x0f, 0x1e, 0x1e, 0x3c, 0x7c, 0x78, 0x78, 0xf0, 0xf0, 0xf1, 0xf3, 0xf3, 0xf7, 0xe7, 0xef, \r\n0xef, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x7e, 0x7e, 0x7e, 0x3f, 0x1f, 0x1f, 0x0f, 0x0f, \r\n0x07, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r\n};\r\n\r\n// WoW logo\r\nconst unsigned char wowLogo [] = {\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xe0, \r\n0xf0, 0xf8, 0xf8, 0xfc, 0xfe, 0xfe, 0x3e, 0x3f, 0x3f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, \r\n0x1f, 0x1f, 0x0f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x3f, 0x3e, 0x7e, 0xfc, 0xfc, 0xf8, 0xf8, 0xf0, \r\n0xf0, 0xe0, 0xe0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xe0, 0xf0, 0xfc, 0xfe, 0xff, 0x7f, 0x3f, 0x6f, 0x67, \r\n0xe3, 0xe3, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe3, \r\n0xe3, 0xef, 0x3f, 0x7f, 0xff, 0xfe, 0xfc, 0xf8, 0xe0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0xf8, 0xfe, 0xff, 0xff, 0xff, 0x1f, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, \r\n0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, \r\n0xff, 0xfc, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, \r\n0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0f, 0xff, 0xff, 0xff, 0xfe, 0xf8, 0xc0, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0xf8, 0xfe, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xe0, 0x80, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x01, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x03, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x1f, 0x3f, 0x7f, 0xff, 0xfe, 0xfc, 0xf0, 0xe0, \r\n0xc0, 0xc0, 0x80, 0x00, 0x00, 0x61, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x63, \r\n0x00, 0x67, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x73, 0x40, 0x80, 0x80, 0xc0, \r\n0xc0, 0xe0, 0xf8, 0xfc, 0xff, 0xff, 0x7f, 0x1f, 0x0f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x07, 0x0f, \r\n0x0f, 0x1f, 0x1f, 0x3f, 0x7e, 0x7e, 0xfc, 0xfc, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf0, 0xf0, 0xf0, \r\n0xf0, 0xf0, 0xf0, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xfc, 0x7c, 0x7c, 0x7e, 0x3f, 0x1f, 0x1f, 0x1f, \r\n0x0f, 0x0f, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r\n};\r\n\r\n// empty no logo\r\nconst unsigned char noLogo [] = {\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r\n};\r\n\r\n// ytmusic logo\r\nconst unsigned char ytmusicLogo [] = {\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, \r\n0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xe0, 0xf0, \r\n0xf8, 0xfc, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfc, 0xfc, 0xf8, \r\n0xf0, 0xe0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xf0, 0xfc, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xdf, 0xe7, 0xf7, 0xfb, 0xfd, 0xfd, 0x3e, 0x7e, 0x7e, 0xfe, \r\n0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xf9, 0xfb, 0xf7, 0xef, 0x9f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xfc, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0x80, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x80, \r\n0x81, 0xc1, 0xc3, 0xe3, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3c, 0xc1, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x3f, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xf9, 0xf7, 0xef, 0xdf, 0xdf, 0xbf, 0xbe, 0x3e, 0x7f, 0x7f, \r\n0x7f, 0x7f, 0xbf, 0xbf, 0xbf, 0xdf, 0xcf, 0xef, 0xf3, 0xf9, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0x7f, 0x1f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x0f, \r\n0x1f, 0x3f, 0x3f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x7f, 0x3f, 0x1f, 0x0f, \r\n0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x03, 0x07, 0x07, 0x07, \r\n0x07, 0x07, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r\n};\r\n\r\n// edge logo\r\nconst unsigned char edgeLogo [] = {\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, \r\n0xe0, 0xf0, 0xf8, 0xf8, 0xfc, 0xfc, 0xfc, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfc, 0xfc, 0xfc, 0xf8, 0xf8, 0xf0, \r\n0xf0, 0xe0, 0xc0, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xe0, 0xf8, 0xfc, 0x7e, 0x7f, 0xbf, 0xbf, 0xbf, \r\n0xbf, 0xff, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xbf, 0xbf, 0x7f, 0x7f, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xf8, 0xf0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xf7, 0xfb, 0xfd, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x7f, 0x3f, 0x3f, 0x3f, 0x1f, 0x1e, \r\n0x1e, 0x1d, 0x3b, 0x27, 0x0f, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0x7f, 0xbf, 0xcf, 0xf3, 0xfd, 0xfe, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x0f, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x01, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0x03, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xf0, 0xe0, 0xc0, 0x80, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, \r\n0x1f, 0x1f, 0x1f, 0x1f, 0x0f, 0x0f, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x1f, 0x3f, 0x7f, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xf0, 0xcf, 0xbf, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xfe, 0xfc, 0xfc, 0xf8, 0xf8, 0xf8, 0xf8, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, \r\n0xf0, 0xf8, 0xf8, 0xf8, 0x78, 0x3c, 0x1c, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, \r\n0x07, 0x0f, 0x1f, 0x1f, 0x3f, 0x3f, 0x7e, 0x7c, 0x79, 0x7b, 0xf7, 0xf7, 0xef, 0xcf, 0xdf, 0xdf, \r\n0xbf, 0xbf, 0xbf, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x3f, 0x3f, 0x1f, 0x1f, 0x0f, 0x0f, \r\n0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r\n};\r\n\r\n//firefox logo\r\nconst unsigned char firefoxLogo [] = {\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0xc0, 0xf0, 0xf8, 0xfc, 0xfc, 0xfe, 0xfe, 0xf8, 0xf0, 0xc0, 0x80, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfc, \r\n0x00, 0x80, 0xc0, 0xe0, 0xe0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0xc0, 0xc0, 0x60, \r\n0x7c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfc, \r\n0xf8, 0xe0, 0xc0, 0x80, 0x20, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xf8, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xf8, 0xf0, 0xe1, 0xe0, 0xc0, 0x80, 0x80, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x21, 0x63, 0xe7, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfc, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x0f, 0x0f, 0x0f, 0x07, 0x07, 0x07, 0x07, 0x03, 0x03, 0x01, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xfe, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, 0xf0, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x1f, 0x3f, 0x7f, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, \r\n0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, \r\n0x07, 0x07, 0x0f, 0x1f, 0x1f, 0x3f, 0x3f, 0x3f, 0x7f, 0x7f, 0x7f, 0x7f, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0x7f, 0x7f, 0x7f, 0x7f, 0x3f, 0x3f, 0x3f, 0x1f, 0x1f, 0x0f, 0x0f, 0x07, \r\n0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r\n};\r\n\r\n//safari logo\r\nconst unsigned char safariLogo [] = {\r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, \r\n0x60, 0x30, 0x18, 0x18, 0x08, 0x0c, 0x0c, 0x86, 0x06, 0x06, 0x02, 0x03, 0x03, 0x03, 0x03, 0xe3, \r\n0xe3, 0x03, 0x03, 0x03, 0x03, 0x02, 0x06, 0x06, 0x86, 0x0c, 0x0c, 0x08, 0x18, 0x18, 0x30, 0x60, \r\n0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xe0, 0x38, 0x1c, 0x0e, 0x03, 0x03, 0x00, 0x00, \r\n0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0xc0, 0xc0, 0x20, 0x10, \r\n0x00, 0x00, 0x01, 0x03, 0x0e, 0x1c, 0x38, 0xe0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x80, 0xf8, 0x3e, 0x07, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x80, 0xc0, 0xe0, 0xe0, 0xf0, 0xf8, 0xf8, 0xfc, 0x7e, 0x3e, 0x0f, 0x07, 0x01, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x00, 0x00, 0x07, 0x3e, 0xf8, 0x80, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x60, 0x30, 0x0c, 0x06, 0x07, 0x0f, \r\n0x9f, 0xbf, 0x7f, 0x3f, 0x1f, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x01, 0x1f, 0x7c, 0xe0, 0x00, 0x00, 0x00, 0x10, 0x18, 0x08, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x80, 0xc0, 0xf0, 0xd8, 0x46, 0x23, 0x30, 0x18, 0x08, 0x04, 0x06, 0x02, 0x01, \r\n0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0xe0, 0xfc, 0x1f, 0x01, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x1c, 0x38, 0x70, 0xc0, 0x80, 0x00, 0x00, \r\n0x08, 0x04, 0x03, 0x03, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, \r\n0x00, 0x00, 0x80, 0xc0, 0x70, 0x38, 0x1c, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, \r\n0x06, 0x0c, 0x18, 0x18, 0x10, 0x30, 0x30, 0x61, 0x60, 0x60, 0x40, 0xc0, 0xc0, 0xc0, 0xc0, 0xc7, \r\n0xc7, 0xc0, 0xc0, 0xc0, 0xc0, 0x40, 0x60, 0x60, 0x63, 0x30, 0x30, 0x30, 0x18, 0x18, 0x0c, 0x06, \r\n0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r\n};\r\n\r\n//zeeuws' logo\r\nconst unsigned char zeeuwsLogo [] = {\r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, \r\n0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x03, 0x03, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x0f, 0x0f, 0x07, 0x07, \r\n0x03, 0x03, 0x07, 0x07, 0x07, 0x0f, 0x0f, 0x0f, 0x0f, 0x1f, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x07, 0x01, 0x00, 0x00, 0x01, \r\n0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x13, \r\n0x1f, 0x3f, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x3f, 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfe, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xef, 0xff, 0xff, 0xff, 0xfe, 0x10, 0x80, 0xf0, 0x00, 0xf8, \r\n0xfe, 0xff, 0xff, 0xff, 0xef, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfc, 0x00, 0x00, 0x00, \r\n0x07, 0xcf, 0x8f, 0x1f, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xc1, 0x80, 0x00, 0x3f, 0x7c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x02, 0x06, 0x06, 0xee, 0xce, 0xce, 0xce, 0x66, 0x66, 0x72, 0x78, 0xfc, 0xf3, 0xcb, 0xc2, 0xe0, \r\n0xf8, 0xf2, 0xe2, 0xe6, 0xee, 0xce, 0xce, 0xce, 0xce, 0xc6, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x20, 0x3f, 0x1f, 0x8f, 0x60, 0x3f, 0x3f, 0xff, 0x7f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x3f, 0x7f, 0xff, 0xff, 0xf8, 0xe0, 0xc0, 0xd0, 0xd0, 0xd0, 0xd0, 0xc0, 0xe0, \r\n0xfc, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x3f, 0x1f, 0x81, 0xc0, 0xe0, 0xf8, 0xf8, 0xfc, 0xfe, \r\n0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0x60, 0x48, 0x40, 0x20, 0x97, 0xe7, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x0e, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0xf9, 0x09, 0x03, 0x03, 0x03, 0x03, 0x03, \r\n0x09, 0x19, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x1f, 0xff, 0x7f, 0x1f, 0x07, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x03, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0e, 0x00, 0x00, 0x00, 0x00, \r\n0x06, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, \r\n0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \r\n0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff\r\n};\r\n"
  },
  {
    "path": "NK2Tray_Display/NK2Tray_DisplayFW_V2/readme.md",
    "content": "# NK2Tray_Display Firmware Upgrade\r\n\r\n### Almost complete rewrite of the firmware, addressing some points by chaosgabe\r\n\r\n## New Features:\r\n- WiFi Connection Manager added (no need to edit things like wifi settings in the code)\r\n- Webinterface added (you can choose which display should show which icon)\r\n- Always on mode added (displays are always on, can be disabled in order to get the old \"ping style\")\r\n- Firmware Update OTA implemented\r\n- Settings are stored on chip\r\n- Old \"Ping style\" got a timeout feature (variable seconds without Ping response will disable the displays)\r\n- more Icons added\r\n- even more Icons added\r\n\r\n\r\n## Using\r\nAfter first flashing of this firmware, the device will set up his own ssid (NK2Tray-Display) to configure the connection to wifi.\r\nWhen connected, you should get pointed to the config page. if not, navigate to http://192.168.4.1\r\nafter setting up the wifi, the device will restart and show its IP address on the displays.\r\nThe booting up screen will disappear after 10 seconds.\r\nAfter that, you can access the webinterface by opening the ip via browser.\r\nHere you can do all your settings. after pressing \"save changes\", all settings will be stored to the eeprom.\r\nThe stored settings are loaded on every bootup.\r\n\r\nIf you experience bugs, please let me know.\r\n\r\n\r\n## All Icons:\r\n- Chrome\r\n- Discord\r\n- Edge\r\n- Empty (literally empty, all pixels off)\r\n- Firefox\r\n- Focus (for focussed windows)\r\n- Gaming\r\n- Master (for Master volume)\r\n- Mic\r\n- Misc\r\n- Mumble\r\n- Opera GX\r\n- Plex\r\n- Safari\r\n- Spotify\r\n- System Sounds (Windows Logo)\r\n- Teams\r\n- Teamspeak\r\n- Unassigned\r\n- World of Warcraft\r\n- YT-Music\r\n"
  },
  {
    "path": "NK2Tray_Display/NK2Tray_DisplayFW_V2/webServer.ino",
    "content": "/*\r\n\r\nESP8266_ArtNetNode_DMX - webServer.ino\r\nCopyright (c) 2015, Matthew Tong    \r\nhttps://github.com/mtongnz/ESP8266_ArtNetNode_DMX\r\n\r\nThis program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public\r\nLicense as published by the Free Software Foundation, either version 3 of the License, or (at your option) any\r\nlater version.\r\n\r\nThis program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied\r\nwarranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\r\n\r\nYou should have received a copy of the GNU General Public License along with this program.\r\nIf not, see http://www.gnu.org/licenses/\r\n\r\n*/\r\n\r\n\r\n/////////  Web Page & CSS - stored to flash memory ////////////\r\n\r\nconst char css[] PROGMEM = \"body {text-align:center;background:#333;}\\n\"\r\n    \"table {margin-left:auto;margin-right:auto;max-width:500px;width:100%;border-collapse:collapse;border:none;}\\n\"\r\n    \"th {height:40px;background:#666;color:white;font-weight:bold;border:none;}\\n\"\r\n    \".mini_head {height:20px;background:#999;}\\n\"\r\n    \"td {padding:6px;border:1px solid #ccc;background:#eee;text-align:left;border:none; position: relative;}\\n\"\r\n    \".left {width:120px;text-align:right;vertical-align:top;}\\n\"\r\n    \".centre {text-align: center;}\\n\"\r\n    \"input:not(.button) {float: left;}\\n\"\r\n    \"input:not(.number):not(.radio):not(.button):not(.checkbox) {width: 100%;}\\n\"\r\n    \"#viewWifiPass {width:18px, height:18px; position: absolute; top: 7px; right: 10px; }\\n\"\r\n    \".number {width:50px;}\\n\"\r\n    \".button {width:150px;margin:10px;}\\n\"\r\n    \".smallButton {width:80px;}\\n\"\r\n    \".static_table {border-collapse:collapse;}\\n\"\r\n    \"p {padding:0px;margin:0px;font-size:14px; clear: both;}\\n\"\r\n    \"a {color:#00A;text-decoration:none;}\\n\"\r\n    \"a:hover {color:#00F;text-decoration:underline;}\\n\"\r\n    \".bigLink {color: white;}\\n\"\r\n    \".round-button {display:block; float: left; margin-right: 7px; width:14px; height:14px; font-size:14px; line-height:14px; border-radius: 50%; color:#ffffff; text-align:center; text-decoration:none; background: #5555ff; box-shadow: 0 0 2px #9999ff; font-weight:bold; font-family: 'Comic Sans', serif;}\";\r\n    \r\nconst char page_head[] PROGMEM = \"<html><head><title>NK2Tray Display</title>\\n\"\r\n    \"<link rel='stylesheet' type='text/css' href='/style.css'>\\n\"\r\n    \"<meta name='viewport' content='width=400'>\"\r\n    \"</head><body>\\n\"\r\n    \"<table id='wrap'>\\n\";\r\n\r\nconst char home_top[] PROGMEM = \"<tr><th colspan=5><a href='/' class='bigLink'>Home</a></th></tr>\"\r\n    \"<form method='POST' action='/save' name='Settings'>\\n\";\r\n\r\nconst char save_top[] PROGMEM = \"<tr><th><a href='/' class='bigLink'>Home</a></th></tr><tr><td><center>\";\r\n\r\nconst char save_tail[] PROGMEM = \"</center></td></tr></table></body></html>\";\r\n    \r\nconst char form_tail[] PROGMEM = \"<tr><th colspan=5 class='centre'>\\n\"\r\n    \"<input type='hidden' name='savechanges' value='yes'>\\n\"\r\n    \"<input type='submit' value='Save Changes' class='button'>\\n\"\r\n    \"</th></tr></form>\\n\"\r\n    \"</table><br /></body>\"\r\n    \"</html>\";\r\n\r\n/* getFlashString()\r\n *  Get our strings stored in flash memory\r\n */\r\nString getFlashString(const char *fStr) {\r\n  int len = strlen_P(fStr);\r\n  char buffer[len+1];\r\n  int k;\r\n  \r\n  for (k = 0; k < len; k++)\r\n    buffer[k] =  pgm_read_byte_near(fStr + k);\r\n  \r\n  buffer[k] = 0;\r\n  \r\n  return String(buffer);\r\n}\r\n\r\n\r\n\r\n/* startWebServer()\r\n *  Very self explanitory - it starts our webserver\r\n *  Sets the handlers for the various pages we will serve\r\n */\r\nvoid startWebServer() {\r\n  webServer.on(\"/\", webHome);\r\n  webServer.on(\"/save\", webSave);\r\n  webServer.on(\"/style.css\", webCSS);\r\n  webServer.onNotFound(webNotFound);\r\n\r\n  //MDNS.begin(wifiSSID);\r\n  webServer.begin();\r\n  //MDNS.addService(\"http\", \"tcp\", 80);\r\n  \r\n  #ifdef VERBOSE\r\n    Serial.println(\"HTTP server started\");\r\n  #endif\r\n}\r\n\r\n\r\n\r\n/* webHome()\r\n *  Our main web page.\r\n */\r\nvoid webHome() {\r\n  \r\n  #ifdef VERBOSE\r\n    Serial.println(\"HTTP Request Received\");\r\n  #endif\r\n  \r\n  // Initialize our page from our flash strings\r\n  String message = getFlashString(page_head);\r\n  message += getFlashString(home_top);\r\n\r\n  // Our MAC Address\r\n  message += \"<tr><td class='left'>Mac Address</td><td colspan='4'>\"\r\n        + MAC_address\r\n        + \"</td></tr>\";\r\n\r\n  // Always on:\r\n  message += \"<tr><td class='left'>Always on Mode</td><td colspan='4'>\";\r\n  message += \"<input type='checkbox' name='always_on' value='yes'\";\r\n  if (always_on)\r\n  {\r\n    message += \" checked\";\r\n  }\r\n  message += \"></td></tr>\";\r\n  \r\n  // IP\r\n  message += \"<tr class='static_table'>\";\r\n  message += \"<td class='left'>Remote IP</td>\\n\";\r\n  for (int x = 0; x < 4; x++) {\r\n    message += \"<td><input type='number' name='ip_\";\r\n    message += char(x+48);\r\n    message += \"' value='\"\r\n        + String(remote_ip[x])\r\n        + \"' min=0 max=255 class='number'></td>\\n\";\r\n  }\r\n  message += \"</tr>\\n\";\r\n\r\n  message += \"<tr><td class='left'>Ping interval</td><td colspan='4'>\";\r\n  message += \"<input type='number' name='pint' value='\" + String(interval / 1000) + \"' min='1' max='600' class='number'></td>\\n</tr>\\n\";\r\n\r\n  message += \"<tr class='disp_config'>\";\r\n  message += \"<td align='center' colspan='5'><div align='center'>Display Config</div></td></tr>\\n<tr>\";\r\n  \r\n  for (int i = 0; i <= 7; i++)\r\n  {\r\n    message += \"<td class='left' colspan='2'>Display \"+ String(i) + \": </td><td align='center' colspan='3'><select name='displayconfig\"+String(i)+\"' id='\"+String(i)+\"'>\\n\";\r\n    for (int x = 0; x <= 20; x++)\r\n    {\r\n      message += \"<option value='\"+String(x)+\"'\";\r\n      if (display[i] == x) {\r\n        message += \" selected='selected'\";\r\n      }\r\n      message += \">\"\r\n      + icons[x]\r\n      + \"</option>\\n\";\r\n    }\r\n    message += \"</select></td></tr><br><br>\\n\";\r\n  }\r\n  \r\n  message += \"</table>\\n<table>\\n\";\r\n  \r\n  // Add the end of the form & page\r\n  message += getFlashString(form_tail);\r\n\r\n  // Send to the client\r\n  webServer.sendHeader(\"Connection\", \"close\");\r\n  webServer.send(200, \"text/html\", message);\r\n  \r\n}\r\n\r\n\r\n\r\n/* webSave()\r\n *  Handle the Save buttons being pressed on web page.\r\n *  Copy data into our global variables.\r\n *  Verifies data then calls our saveSettings function.\r\n *  Resets node if the save and reset button clicked\r\n */\r\nvoid webSave() {\r\n \r\n  \r\n  #ifdef VERBOSE\r\n    Serial.println(\"HTTP Save Request includes arguements\");\r\n  #endif\r\n  \r\n  char * split;\r\n  char tmpArg[30];\r\n  String message = \"\";\r\n\r\n  if (webServer.arg(\"savechanges\") == \"yes\") {\r\n    \r\n      #ifdef VERBOSE\r\n    Serial.println(\"HTTP Post check ok\");\r\n  #endif\r\n  \r\n    bool err = 0;\r\n    IPAddress tmp1(0,0,0,0);\r\n    IPAddress tmp2(0,0,0,0);\r\n    IPAddress tmp3(0,0,0,0);\r\n    int x;\r\n\r\n \r\n    for (x = 0; x < 4; x++) {\r\n      char id[5] = \"ip_\";\r\n      id[3] = x+48;\r\n      id[4] = 0;\r\n      webServer.arg(id).toCharArray(tmpArg, 30);\r\n      tmp1[x] = atoi(tmpArg);\r\n      if (tmp1[x] < 0 || tmp1[x] > 255) {\r\n        err = 1;\r\n      } \r\n    }\r\n    \r\n    if (err == 1) {\r\n      message += \"- Invalid IP Address<br />\";\r\n    err = 0;\r\n    }\r\n    // If we dont have error message, set the IP variables\r\n    if (message.length() == 0) {\r\n      // All IPs are valid, store them\r\n      remote_ip = tmp1;\r\n    }\r\n    \r\n    int newinterval = webServer.arg(\"pint\").toInt();\r\n    if (newinterval < 0 || newinterval > 600) {\r\n      message += \"- Invalid Ping interval!<br />\";\r\n      #ifdef VERBOSE\r\n        Serial.print(\"Interval error: \");\r\n        Serial.println(interval);\r\n      #endif  \r\n    } else {\r\n      interval = newinterval * 1000;\r\n      #ifdef VERBOSE\r\n        Serial.print(\"new interval: \");\r\n        Serial.println(interval);\r\n      #endif\r\n    }\r\n        \r\n  for (int x = 0; x <= 7; x++)\r\n  {\r\n \r\n    char displayconfigi[14] = \"displayconfig\";\r\n    displayconfigi[13] = x+48;\r\n    displayconfigi[14] = 0;\r\n    display[x] = webServer.arg(displayconfigi).toInt();\r\n  }\r\n  if (webServer.arg(\"always_on\") == \"yes\")\r\n  {\r\n    always_on = true;\r\n  } else {\r\n    always_on = false;\r\n  }\r\n  // Save settings to EEPROM\r\n  if (saveSettings()) {\r\n    // IP issues from above - the IPs didn't get saved but the rest did\r\n    if (message.length() > 0) {\r\n      message = \"Some changes saved.  There were the following issues:<br />\\n<br />\\n\" + message;\r\n    } else {\r\n      message += \"Changes Saved.\";\r\n      refresh_displays = true;\r\n    }\r\n  // Error saving our settings to EEPROM\r\n  } else {\r\n    message = \"Error saving settings.  Please try again.\";\r\n  }\r\n\r\n  //Generate final page using flash strings\r\n  String tmp = getFlashString(page_head);\r\n  tmp += getFlashString(save_top);\r\n  tmp += message;\r\n  tmp += getFlashString(save_tail);\r\n\r\n  // Send page\r\n  webServer.sendHeader(\"Connection\", \"close\");\r\n  webServer.send(200, \"text/html\", tmp);\r\n  \r\n  } else {\r\n    #ifdef VERBOSE\r\n    Serial.println(\"HTTP POST check not ok\");\r\n  #endif\r\n}\r\n}\r\n\r\n\r\n\r\n/* webCSS()\r\n *  Send our style sheet to the web client\r\n */\r\nvoid webCSS() {\r\n  webServer.sendHeader(\"Connection\", \"close\");\r\n  webServer.send(200, \"text/html\", getFlashString(css));\r\n}\r\n\r\n/* webNotFound()\r\n *  display a 404 page\r\n */\r\nvoid webNotFound() {\r\n  // Check if we're recalling a stored DMX state\r\n  char charBuf[webServer.uri().length() + 1];\r\n  webServer.uri().toCharArray(charBuf, webServer.uri().length() + 1);\r\n  char* tmp = strtok(charBuf, \"/.\");\r\n    \r\n  #ifdef VERBOSE\r\n    Serial.println(\"Sending 404\");\r\n    Serial.print(\"URI: \");\r\n    Serial.println(webServer.uri());\r\n    Serial.print(\"Method: \");\r\n    Serial.println(( webServer.method() == HTTP_GET ) ? \"GET\" : \"POST\");\r\n    Serial.print(\"Arguments: \");\r\n    Serial.println(webServer.args());\r\n  #endif\r\n\r\n  // Generate page from flash strings\r\n  String message = getFlashString(page_head);\r\n  message += getFlashString(save_top);\r\n  message += \"404: File Not Found\\n<br />\\n<br />\";\r\n  message += \"URI: \";\r\n  message += webServer.uri();\r\n  message += \"<br />\\n<br />\\n<a href='/'>Go to settings page</a>\";\r\n  message += getFlashString(save_tail);\r\n\r\n  // Send page\r\n  webServer.sendHeader(\"Connection\", \"close\");\r\n  webServer.send(200, \"text/html\", message);\r\n}\r\n"
  },
  {
    "path": "NK2Tray_Display/Readme.md",
    "content": "<img src=\"https://media.discordapp.net/attachments/532233406482743300/653946714561970176/IMG_20190927_114511.jpg?width=841&height=631\">\n\n# NK2Tray_Display\nA simple addon for the Korg nanoKONTROL2 providing 8 tiny OLED displays to show the software that is controlled by the particular fader. The displays are controlled by a ESP8266 via an I2C multiplexer.\n\n## alternate Firmware\nalternative firmware in the Subfolder \"NK2Tray_DisplayFW_v2\". See readme in this folder.\n\n#### The good\n* Easy to read even in daylight\n* OLED displays do not use energy when the don´t show anything, so standby is pretty low\n* Will automatically switch off the displays when the host can no longer be pinged\n\n#### The bad\n* Displays might burn in, have not noticed that yet though\n* No fixation between the NK2 and the display yet\n\n#### The ugly\n* ~~The shown icons are hardcoded in the arduino sketch~~\n* ~~The host ip is hardcoded in the arduino sketch~~\n\n  (Solved thanks to the new firmware V1 from piLo)\n\n## How to build you own\nYou will need a handfull of modules easily available online, the PCB and a few 3d printed parts.\nI provide links to the used modules in the BOM as well as an description in case those links die. \nThe 3d files are in this folder, as well as the gerber files for the PCB and the arduino sketch.\n\n\n## Disclaimer\nI am not a software developer neither am i an electrical engineer. So basically i have no clue on what the best practices, general rules or even the correct terms regarding software/hardware are.\nIf you do know those things please tell me, i will try to learn.\nI am also not an native English speaker.\n\n\n\n\n\n\n\n"
  },
  {
    "path": "README.md",
    "content": "# NOTE: The group of developers for NK2Tray are largely inactive. <br> A rewrite in a language more familiar to the original developer (and thus far for likely to be maintained) is in early stages here: \n## • [ho0ber/Havomi](https://github.com/ho0ber/havomi)\n### Also consider checking out these excellent alternative projects:\n• [Midi Mixer](https://www.midi-mixer.com/)<br>\n• [MidiManager](https://jitse-ten-hove.itch.io/midimanager)\n\n# <img src=\"https://raw.githubusercontent.com/ho0ber/NK2Tray/master/NK2Tray/nk2tray.ico\" height=\"24\"> NK2Tray\nA simple system tray utility to control the Windows Audio Mixer with a Korg nanoKONTROL2 and other similar control surfaces.\n\n(A rewrite of [nk2-audio](https://github.com/ho0ber/nk2-audio))\n\n## Download\nTo download the latest version of NK2Tray, go to this project's [**Releases page**](https://github.com/ho0ber/NK2Tray/releases).\n\n## Problemsolving and Installation Instructions\n\nThe [installation instructions](https://github.com/ho0ber/NK2Tray/wiki/Installation-Instructions) and a solution to the [most common problems](https://github.com/ho0ber/NK2Tray/wiki/Frequent-Problems) can be found in our [WIKI](https://github.com/ho0ber/NK2Tray/wiki)\nIf you cannot resolve your problems here simply ask in our [Troubleshooting Discord Channel](https://discord.gg/6ekacWc)\n\n## Getting Involved\nTo help test or contribute, I encourage you to join our discord: https://discord.gg/BtVTYxp\n\nCurrent development work is being tracked in this repository's [Github Project](https://github.com/ho0ber/NK2Tray/projects/1).\n\n## Disclaimer\nI'm not a Windows developer. There's a lot in here that's far from best practices, and I welcome you to help improve the code. This project is an attempt to significantly improve the stability and extensibility of a project that was first written in AutoHotkey, so even my most clumsy attempts are already much better than the old codebase. Please reach out to me if you have experience fighting with Windows in code and want to take an active role in this project.\n\nAlso, I'm pretty sure I have to release this under the Ms-PL license if I want it to be open source, because that's what [NAudio](https://github.com/naudio/NAudio) is licensed under.\n\n## Project Goals\n* Improved stability over nk2-audio by means of better maintainability\n* Reduced conflicts with games by not using AutoHotkey (which is rejected by some anti-cheat measures)\n* Additional device support with minimal additional coding/configuration\n* Greatly improved potential for features in the long term\n* Improved performance and precision over nk2-audio when setting volumes\n\n## Planned Features\n- [x] Tray menu configuration of faders to volume mixer sessions\n- [x] Configurable Master(device) volume and system sounds support\n- [x] Midi feedback to light controls upon activation\n- [x] On the fly binding of sessions using \"S\" buttons\n- [x] Media button support\n- [x] Persistence of configuration across sessions (restoring on reopening NK2Tray)\n- [x] Multi-session differentiation in persistence (2 instances of Discord, for example)\n- [x] Support for processes changing (closing/reopening application) and retaining a handle to its session\n- [ ] Detection of midi device connect/disconnect\n- [ ] Selectable input/output midi devices (defaulting to nano)\n- [ ] Support for common amazon clones of nanokontrol2\n- [ ] (Eventual) support for advanced control surface features (motorized faders, volume meters, scribble strips)\n\n## Currently Supported Devices\nAt the moment the support for the MIDI devices is limited. It will be extended in the future.\n\nThe currently supported MIDI devices are listed in the [Device Support Matrix](https://github.com/ho0ber/NK2Tray/wiki/Device-Support-Matrix)\n\n## Attribution & Acknowledgements\n * <img src=\"https://raw.githubusercontent.com/ho0ber/NK2Tray/master/NK2Tray/nk2tray.ico\" height=\"24\"> [NK2 Tray icon](NK2Tray/nk2tray.ico) courtesy of [Dave Savic](https://www.iconfinder.com/icons/2001872/blue_level_levels_mixer_settings_shadow_volume_icon)\n * Midi and Core Audio thanks to [NAudio](https://github.com/naudio/NAudio)\n\n"
  },
  {
    "path": "license.txt",
    "content": "Microsoft Public License (Ms-PL)\n\nThis license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software.\n\n1. Definitions\n\nThe terms \"reproduce,\" \"reproduction,\" \"derivative works,\" and \"distribution\" have the same meaning here as under U.S. copyright law.\n\nA \"contribution\" is the original software, or any additions or changes to the software.\n\nA \"contributor\" is any person that distributes its contribution under this license.\n\n\"Licensed patents\" are a contributor's patent claims that read directly on its contribution.\n\n2. Grant of Rights\n\n(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.\n\n(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.\n\n3. Conditions and Limitations\n\n(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.\n\n(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.\n\n(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.\n\n(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.\n\n(E) The software is licensed \"as-is.\" You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. "
  }
]