aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfffw2015-02-13 15:20:13 +0800
committerfffw2015-02-13 15:20:13 +0800
commitc00cfb38ee3aee8da409898fed17e80716095e89 (patch)
treee6997d1ab53bfb8e1dfeafec7e239f8cfbc35838
parent85d3e528d5a1d1ef8b60dcafc901c633343b4a37 (diff)
parent6a81309bde4a67b2d5d1cb57b2e89945ba63fde6 (diff)
downloadsystray-issue-2143-lib.tar.bz2
merge xcompileissue-2143-lib
-rw-r--r--.gitignore2
-rw-r--r--README.md4
-rw-r--r--lib/systray_darwin.c16
-rwxr-xr-xsystray.dllbin0 -> 9728 bytes
-rw-r--r--systray.go71
-rw-r--r--systray.h4
-rw-r--r--systray.libbin0 -> 2450 bytes
-rwxr-xr-xsystray/systray.sdfbin0 -> 11423744 bytes
-rwxr-xr-xsystray/systray.sln20
-rwxr-xr-xsystray/systray.suobin0 -> 9728 bytes
-rwxr-xr-xsystray/systray/ReadMe.txt48
-rwxr-xr-xsystray/systray/dllmain.cpp19
-rwxr-xr-xsystray/systray/stdafx.cpp8
-rwxr-xr-xsystray/systray/stdafx.h17
-rwxr-xr-x[-rw-r--r--]systray/systray/systray.cpp (renamed from systray_windows.c)512
-rwxr-xr-xsystray/systray/systray.h10
-rwxr-xr-xsystray/systray/systray.vcxproj100
-rwxr-xr-xsystray/systray/systray.vcxproj.filters42
-rwxr-xr-xsystray/systray/systray.vcxproj.user3
-rwxr-xr-xsystray/systray/targetver.h8
-rw-r--r--systray_linux.c17
-rw-r--r--systray_nonwindows.go71
-rw-r--r--systray_windows.go151
-rw-r--r--systraydll_windows.go3
24 files changed, 783 insertions, 343 deletions
diff --git a/.gitignore b/.gitignore
index 85b5294..6cdccf3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,5 @@ example/example
*~
*.swp
*.exe
+Release
+Debug
diff --git a/README.md b/README.md
index 46c9cfd..c2a83fc 100644
--- a/README.md
+++ b/README.md
@@ -28,8 +28,8 @@ Checked menu item not implemented on Linux yet.
### Windows
-Install [MinGW-W64](http://sourceforge.net/projects/mingw-w64) as it has up to date SDK headers we require.
-
+Use the Visual Studio solution to build systray.dll and then check that in to
+Git. Make sure to target Windows XP.
## Try
diff --git a/lib/systray_darwin.c b/lib/systray_darwin.c
index 50a37d8..fffc49e 100644
--- a/lib/systray_darwin.c
+++ b/lib/systray_darwin.c
@@ -4,27 +4,26 @@
@interface MenuItem : NSObject
{
@public
- NSString* menuId;
+ NSNumber* menuId;
NSString* title;
NSString* tooltip;
short disabled;
short checked;
}
--(id) initWithId: (const char*)theMenuId
+-(id) initWithId: (int)theMenuId
withTitle: (const char*)theTitle
withTooltip: (const char*)theTooltip
withDisabled: (short)theDisabled
withChecked: (short)theChecked;
@end
@implementation MenuItem
- -(id) initWithId: (const char*)theMenuId
+ -(id) initWithId: (int)theMenuId
withTitle: (const char*)theTitle
withTooltip: (const char*)theTooltip
withDisabled: (short)theDisabled
withChecked: (short)theChecked
{
- menuId = [[NSString alloc] initWithCString:theMenuId
- encoding:NSUTF8StringEncoding];
+ menuId = [NSNumber numberWithInt:theMenuId];
title = [[NSString alloc] initWithCString:theTitle
encoding:NSUTF8StringEncoding];
tooltip = [[NSString alloc] initWithCString:theTooltip
@@ -80,8 +79,8 @@
- (IBAction)menuHandler:(id)sender
{
- NSString* menuId = [sender representedObject];
- systray_menu_item_selected((char*)[menuId cStringUsingEncoding: NSUTF8StringEncoding]);
+ NSNumber* menuId = [sender representedObject];
+ systray_menu_item_selected(menuId.intValue);
}
- (void) add_or_update_menu_item:(MenuItem*) item
@@ -152,9 +151,8 @@ void setTooltip(char* ctooltip) {
runInMainThread(@selector(setTooltip:), (id)tooltip);
}
-void add_or_update_menu_item(char* menuId, char* title, char* tooltip, short disabled, short checked) {
+void add_or_update_menu_item(int menuId, char* title, char* tooltip, short disabled, short checked) {
MenuItem* item = [[MenuItem alloc] initWithId: menuId withTitle: title withTooltip: tooltip withDisabled: disabled withChecked: checked];
- free(menuId);
free(title);
free(tooltip);
runInMainThread(@selector(add_or_update_menu_item:), (id)item);
diff --git a/systray.dll b/systray.dll
new file mode 100755
index 0000000..5fcbf1f
--- /dev/null
+++ b/systray.dll
Binary files differ
diff --git a/systray.go b/systray.go
index bd3441a..38fcd6c 100644
--- a/systray.go
+++ b/systray.go
@@ -5,21 +5,12 @@ Methods can be called from any goroutine except Run(), which should be called at
*/
package systray
-/*
-#cgo LDFLAGS: -L /Users/merlin/workspace/go/src/github.com/getlantern/systray
-#cgo linux pkg-config: gtk+-3.0 appindicator3-0.1
-#cgo windows CFLAGS: -DWIN32 -DUNICODE -D_UNICODE
-#cgo darwin 386 LDFLAGS: -framework Cocoa -lsystray_darwin_386
-#cgo darwin amd64 LDFLAGS: -framework Cocoa -lsystray_darwin_amd64
-
-#include "systray.h"
-*/
-import "C"
import (
- "code.google.com/p/go-uuid/uuid"
"runtime"
"sync"
- "unsafe"
+ "sync/atomic"
+
+ "github.com/getlantern/golog"
)
// MenuItem is used to keep track each menu item of systray
@@ -29,7 +20,7 @@ type MenuItem struct {
ClickedCh chan interface{}
// id uniquely identify a menu item, not supposed to be modified
- id string
+ id int32
// title is the text shown on menu item
title string
// tooltip is the text shown when pointing to menu item
@@ -41,10 +32,14 @@ type MenuItem struct {
}
var (
+ log = golog.LoggerFor("systray")
+
readyCh = make(chan interface{})
clickedCh = make(chan interface{})
- menuItems = make(map[string]*MenuItem)
+ menuItems = make(map[int32]*MenuItem)
menuItemsLock sync.RWMutex
+
+ currentId int32
)
// Run initializes GUI and starts the event loop, then invokes the onReady
@@ -58,31 +53,12 @@ func Run(onReady func()) {
onReady()
}()
- C.nativeLoop()
+ nativeLoop()
}
// Quit the systray and whole app
func Quit() {
- C.quit()
-}
-
-// SetIcon sets the systray icon.
-// iconBytes should be the content of .ico for windows and .ico/.jpg/.png
-// for other platforms.
-func SetIcon(iconBytes []byte) {
- cstr := (*C.char)(unsafe.Pointer(&iconBytes[0]))
- C.setIcon(cstr, (C.int)(len(iconBytes)))
-}
-
-// SetTitle sets the systray title, only available on Mac.
-func SetTitle(title string) {
- C.setTitle(C.CString(title))
-}
-
-// SetTitle sets the systray tooltip to display on mouse hover of the tray icon,
-// only available on Mac.
-func SetTooltip(tooltip string) {
- C.setTooltip(C.CString(tooltip))
+ quit()
}
// Add menu item with designated title and tooltip, returning a channel that
@@ -93,7 +69,7 @@ func SetTooltip(tooltip string) {
//
// AddMenuItem can be safely invoked from different goroutines.
func AddMenuItem(title string, tooltip string) *MenuItem {
- id := uuid.New()
+ id := atomic.AddInt32(&currentId, 1)
item := &MenuItem{nil, id, title, tooltip, false, false}
item.ClickedCh = make(chan interface{})
item.update()
@@ -143,31 +119,14 @@ func (item *MenuItem) update() {
menuItemsLock.Lock()
defer menuItemsLock.Unlock()
menuItems[item.id] = item
- var disabled C.short = 0
- if item.disabled {
- disabled = 1
- }
- var checked C.short = 0
- if item.checked {
- checked = 1
- }
- C.add_or_update_menu_item(
- C.CString(item.id),
- C.CString(item.title),
- C.CString(item.tooltip),
- disabled,
- checked,
- )
+ addOrUpdateMenuItem(item)
}
-//export systray_ready
-func systray_ready() {
+func systrayReady() {
readyCh <- nil
}
-//export systray_menu_item_selected
-func systray_menu_item_selected(cId *C.char) {
- id := C.GoString(cId)
+func systrayMenuItemSelected(id int32) {
menuItemsLock.RLock()
item := menuItems[id]
menuItemsLock.RUnlock()
diff --git a/systray.h b/systray.h
index 88ba563..819b65f 100644
--- a/systray.h
+++ b/systray.h
@@ -1,9 +1,9 @@
extern void systray_ready();
-extern void systray_menu_item_selected(char* menu_id);
+extern void systray_menu_item_selected(int menu_id);
int nativeLoop(void);
void setIcon(const char* iconBytes, int length);
void setTitle(char* title);
void setTooltip(char* tooltip);
-void add_or_update_menu_item(char* menuId, char* title, char* tooltip, short disabled, short checked);
+void add_or_update_menu_item(int menuId, char* title, char* tooltip, short disabled, short checked);
void quit();
diff --git a/systray.lib b/systray.lib
new file mode 100644
index 0000000..d6b210f
--- /dev/null
+++ b/systray.lib
Binary files differ
diff --git a/systray/systray.sdf b/systray/systray.sdf
new file mode 100755
index 0000000..431663e
--- /dev/null
+++ b/systray/systray.sdf
Binary files differ
diff --git a/systray/systray.sln b/systray/systray.sln
new file mode 100755
index 0000000..30c2245
--- /dev/null
+++ b/systray/systray.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual C++ Express 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "systray", "systray\systray.vcxproj", "{7DD84108-D77F-4F51-AC68-5DD13AC1E489}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {7DD84108-D77F-4F51-AC68-5DD13AC1E489}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7DD84108-D77F-4F51-AC68-5DD13AC1E489}.Debug|Win32.Build.0 = Debug|Win32
+ {7DD84108-D77F-4F51-AC68-5DD13AC1E489}.Release|Win32.ActiveCfg = Release|Win32
+ {7DD84108-D77F-4F51-AC68-5DD13AC1E489}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/systray/systray.suo b/systray/systray.suo
new file mode 100755
index 0000000..f2c9d40
--- /dev/null
+++ b/systray/systray.suo
Binary files differ
diff --git a/systray/systray/ReadMe.txt b/systray/systray/ReadMe.txt
new file mode 100755
index 0000000..7e906df
--- /dev/null
+++ b/systray/systray/ReadMe.txt
@@ -0,0 +1,48 @@
+========================================================================
+ DYNAMIC LINK LIBRARY : systray Project Overview
+========================================================================
+
+AppWizard has created this systray DLL for you.
+
+This file contains a summary of what you will find in each of the files that
+make up your systray application.
+
+
+systray.vcxproj
+ This is the main project file for VC++ projects generated using an Application Wizard.
+ It contains information about the version of Visual C++ that generated the file, and
+ information about the platforms, configurations, and project features selected with the
+ Application Wizard.
+
+systray.vcxproj.filters
+ This is the filters file for VC++ projects generated using an Application Wizard.
+ It contains information about the association between the files in your project
+ and the filters. This association is used in the IDE to show grouping of files with
+ similar extensions under a specific node (for e.g. ".cpp" files are associated with the
+ "Source Files" filter).
+
+systray.cpp
+ This is the main DLL source file.
+
+ When created, this DLL does not export any symbols. As a result, it
+ will not produce a .lib file when it is built. If you wish this project
+ to be a project dependency of some other project, you will either need to
+ add code to export some symbols from the DLL so that an export library
+ will be produced, or you can set the Ignore Input Library property to Yes
+ on the General propert page of the Linker folder in the project's Property
+ Pages dialog box.
+
+/////////////////////////////////////////////////////////////////////////////
+Other standard files:
+
+StdAfx.h, StdAfx.cpp
+ These files are used to build a precompiled header (PCH) file
+ named systray.pch and a precompiled types file named StdAfx.obj.
+
+/////////////////////////////////////////////////////////////////////////////
+Other notes:
+
+AppWizard uses "TODO:" comments to indicate parts of the source code you
+should add to or customize.
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/systray/systray/dllmain.cpp b/systray/systray/dllmain.cpp
new file mode 100755
index 0000000..8a4edd3
--- /dev/null
+++ b/systray/systray/dllmain.cpp
@@ -0,0 +1,19 @@
+// dllmain.cpp : Defines the entry point for the DLL application.
+#include "stdafx.h"
+
+BOOL APIENTRY DllMain( HMODULE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved
+ )
+{
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
diff --git a/systray/systray/stdafx.cpp b/systray/systray/stdafx.cpp
new file mode 100755
index 0000000..a71cba8
--- /dev/null
+++ b/systray/systray/stdafx.cpp
@@ -0,0 +1,8 @@
+// stdafx.cpp : source file that includes just the standard includes
+// systray.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/systray/systray/stdafx.h b/systray/systray/stdafx.h
new file mode 100755
index 0000000..7e739d9
--- /dev/null
+++ b/systray/systray/stdafx.h
@@ -0,0 +1,17 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+#include "targetver.h"
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+// Windows Header Files:
+#include <windows.h>
+// Additional required headers
+#include <stdio.h>
+#include <stdlib.h>
+#include <windows.h>
+#include <shellapi.h>
diff --git a/systray_windows.c b/systray/systray/systray.cpp
index ebc0bdd..eb2ea29 100644..100755
--- a/systray_windows.c
+++ b/systray/systray/systray.cpp
@@ -1,268 +1,244 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <windows.h>
-#include <shellapi.h>
-#include "systray.h"
-
-// Message posted into message loop when Notification Icon is clicked
-#define WM_SYSTRAY_MESSAGE (WM_USER + 1)
-
-static NOTIFYICONDATA nid;
-static HWND hWnd;
-static HMENU hTrayMenu;
-
-void reportWindowsError(const char* action) {
- LPTSTR pErrMsg = NULL;
- DWORD errCode = GetLastError();
- DWORD result = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
- FORMAT_MESSAGE_FROM_SYSTEM|
- FORMAT_MESSAGE_ARGUMENT_ARRAY,
- NULL,
- errCode,
- LANG_NEUTRAL,
- pErrMsg,
- 0,
- NULL);
- printf("Systray error %s: %d %s\n", action, errCode, pErrMsg);
-}
-
-wchar_t* UTF8ToUnicode(const char* str) {
- wchar_t* result;
- int textLen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL ,0);
- result = (wchar_t *)calloc((textLen+1), sizeof(wchar_t));
- int converted = MultiByteToWideChar(CP_UTF8, 0, str, -1, (LPWSTR)result, textLen);
- // Ensure result is alway zero terminated in case either syscall failed
- if (converted == 0) {
- reportWindowsError("convert UTF8 to UNICODE");
- result[0] = L'\0';
- }
- return result;
-}
-
-void ShowMenu(HWND hWnd) {
- POINT p;
- if (0 == GetCursorPos(&p)) {
- reportWindowsError("get tray menu position");
- return;
- };
- SetForegroundWindow(hWnd); // Win32 bug work-around
- TrackPopupMenu(hTrayMenu, TPM_BOTTOMALIGN | TPM_LEFTALIGN, p.x, p.y, 0, hWnd, NULL);
-
-}
-
-char* GetMenuItemId(int index) {
- MENUITEMINFO menuItemInfo;
- menuItemInfo.cbSize = sizeof(MENUITEMINFO);
- menuItemInfo.fMask = MIIM_DATA;
- if (0 == GetMenuItemInfo(hTrayMenu, index, TRUE, &menuItemInfo)) {
- reportWindowsError("get menu item id");
- return NULL;
- }
- return (char*)menuItemInfo.dwItemData;
-}
-
-LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
- switch (message) {
- case WM_MENUCOMMAND:
- {
- char * menuId = GetMenuItemId(wParam);
- if (menuId != NULL) {
- systray_menu_item_selected(menuId);
- }
- }
- break;
- case WM_DESTROY:
- Shell_NotifyIcon(NIM_DELETE, &nid);
- PostQuitMessage(0);
- break;
- case WM_SYSTRAY_MESSAGE:
- switch(lParam) {
- case WM_RBUTTONUP:
- ShowMenu(hWnd);
- break;
- case WM_LBUTTONUP:
- ShowMenu(hWnd);
- break;
- default:
- return DefWindowProc(hWnd, message, wParam, lParam);
- };
- break;
- default:
- return DefWindowProc(hWnd, message, wParam, lParam);
- }
- return 0;
-}
-
-void MyRegisterClass(HINSTANCE hInstance, TCHAR* szWindowClass) {
- WNDCLASSEX wcex;
-
- wcex.cbSize = sizeof(WNDCLASSEX);
- wcex.style = CS_HREDRAW | CS_VREDRAW;
- wcex.lpfnWndProc = WndProc;
- wcex.cbClsExtra = 0;
- wcex.cbWndExtra = 0;
- wcex.hInstance = hInstance;
- wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
- wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
- wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
- wcex.lpszMenuName = 0;
- wcex.lpszClassName = szWindowClass;
- wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
-
- RegisterClassEx(&wcex);
-}
-
-HWND InitInstance(HINSTANCE hInstance, int nCmdShow, TCHAR* szWindowClass) {
- HWND hWnd = CreateWindow(szWindowClass, TEXT(""), WS_OVERLAPPEDWINDOW,
- CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
- if (!hWnd) {
- return 0;
- }
-
- ShowWindow(hWnd, nCmdShow);
- UpdateWindow(hWnd);
-
- return hWnd;
-}
-
-
-BOOL createMenu() {
- hTrayMenu = CreatePopupMenu();
- MENUINFO menuInfo;
- menuInfo.cbSize = sizeof(MENUINFO);
- menuInfo.fMask = MIM_APPLYTOSUBMENUS | MIM_STYLE;
- menuInfo.dwStyle = MNS_NOTIFYBYPOS;
- return SetMenuInfo(hTrayMenu, &menuInfo);
-}
-
-BOOL addNotifyIcon() {
- nid.cbSize = sizeof(NOTIFYICONDATA);
- nid.hWnd = hWnd;
- nid.uID = 100;
- nid.uCallbackMessage = WM_SYSTRAY_MESSAGE;
- nid.uFlags = NIF_MESSAGE;
- return Shell_NotifyIcon(NIM_ADD, &nid);
-}
-
-int nativeLoop(void) {
- HINSTANCE hInstance = GetModuleHandle(NULL);
- TCHAR* szWindowClass = TEXT("SystrayClass");
- MyRegisterClass(hInstance, szWindowClass);
- hWnd = InitInstance(hInstance, FALSE, szWindowClass); // Don't show window
- if (!hWnd) {
- return EXIT_FAILURE;
- }
- if (!createMenu() || !addNotifyIcon()) {
- return EXIT_FAILURE;
- }
- systray_ready();
-
- MSG msg;
- while (GetMessage(&msg, NULL, 0, 0)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- return EXIT_SUCCESS;
-}
-
-
-void setIcon(const char* iconBytes, int length) {
- HICON hIcon;
- // This is really hacky, but LoadImage won't let me load an image from memory.
- // So we have to write out a temporary file, load it from there, then delete the file.
-
- // From http://msdn.microsoft.com/en-us/library/windows/desktop/aa363875.aspx
- TCHAR szTempFileName[MAX_PATH+1];
- TCHAR lpTempPathBuffer[MAX_PATH+1];
- int dwRetVal = GetTempPath(MAX_PATH+1, lpTempPathBuffer);
- if (dwRetVal > MAX_PATH+1 || (dwRetVal == 0)) {
- reportWindowsError("get temp icon path");
- return;
- }
-
- int uRetVal = GetTempFileName(lpTempPathBuffer, TEXT("systray_"), 0, szTempFileName);
- if (uRetVal == 0) {
- reportWindowsError("get temp icon file name");
- return;
- }
-
- FILE* fIcon = _wfopen(szTempFileName, TEXT("wb"));
- if (fIcon == NULL) {
- reportWindowsError("open temp icon file to write");
- return;
- }
- ssize_t bytesWritten = fwrite(iconBytes, 1, length, fIcon);
- fclose(fIcon);
- if (bytesWritten != length) {
- printf("error write temp icon file\n");
- } else {
-
- hIcon = LoadImage(NULL, szTempFileName, IMAGE_ICON, 64, 64, LR_LOADFROMFILE);
- if (hIcon == NULL) {
- reportWindowsError("load icon image");
- } else {
-
- nid.hIcon = hIcon;
- nid.uFlags = NIF_ICON;
- Shell_NotifyIcon(NIM_MODIFY, &nid);
- }
- }
- _wremove(szTempFileName);
-
-}
-
-// Don't support for Windows
-void setTitle(char* ctitle) {
- free(ctitle);
-}
-
-void setTooltip(char* ctooltip) {
- wchar_t* tooltip = UTF8ToUnicode(ctooltip);
- wcsncpy(nid.szTip, tooltip, 64);
- nid.uFlags = NIF_TIP;
- Shell_NotifyIcon(NIM_MODIFY, &nid);
- free(tooltip);
- free(ctooltip);
-}
-
-void add_or_update_menu_item(char* menuId, char* ctitle, char* ctooltip, short disabled, short checked) {
- wchar_t* title = UTF8ToUnicode(ctitle);
- MENUITEMINFO menuItemInfo;
- menuItemInfo.cbSize = sizeof(MENUITEMINFO);
- menuItemInfo.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_DATA | MIIM_STATE;
- menuItemInfo.fType = MFT_STRING;
- menuItemInfo.dwTypeData = title;
- menuItemInfo.cch = wcslen(title) + 1;
- menuItemInfo.dwItemData = (ULONG_PTR)menuId;
- menuItemInfo.fState = 0;
- if (disabled == 1) {
- menuItemInfo.fState |= MFS_DISABLED;
- }
- if (checked == 1) {
- menuItemInfo.fState |= MFS_CHECKED;
- }
-
- int itemCount = GetMenuItemCount(hTrayMenu);
- int i;
- for (i = 0; i < itemCount; i++) {
- char * idString = GetMenuItemId(i);
- if (NULL == idString) {
- continue;
- }
- if (strcmp(menuId, idString) == 0) {
- free(idString);
- SetMenuItemInfo(hTrayMenu, i, TRUE, &menuItemInfo);
- break;
- }
- }
- if (i == itemCount) {
- InsertMenuItem(hTrayMenu, -1, TRUE, &menuItemInfo);
- }
- free(title);
- free(ctitle);
- free(ctooltip);
-}
-
-void quit() {
- PostMessage(hWnd, WM_DESTROY, 0, 0);
-}
+// systray.cpp : Defines the exported functions for the DLL application.
+//
+
+// dllmain.cpp : Defines the entry point for the DLL application.
+#include "stdafx.h"
+#include "systray.h"
+
+// Message posted into message loop when Notification Icon is clicked
+#define WM_SYSTRAY_MESSAGE (WM_USER + 1)
+
+static NOTIFYICONDATA nid;
+static HWND hWnd;
+static HMENU hTrayMenu;
+
+void (*systray_menu_item_selected)(int menu_id);
+
+void reportWindowsError(const char* action) {
+ LPTSTR pErrMsg = NULL;
+ DWORD errCode = GetLastError();
+ DWORD result = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
+ FORMAT_MESSAGE_FROM_SYSTEM|
+ FORMAT_MESSAGE_ARGUMENT_ARRAY,
+ NULL,
+ errCode,
+ LANG_NEUTRAL,
+ pErrMsg,
+ 0,
+ NULL);
+ printf("Systray error %s: %d %s\n", action, errCode, pErrMsg);
+}
+
+wchar_t* UTF8ToUnicode(const char* str) {
+ wchar_t* result;
+ int textLen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL ,0);
+ result = (wchar_t *)calloc((textLen+1), sizeof(wchar_t));
+ int converted = MultiByteToWideChar(CP_UTF8, 0, str, -1, (LPWSTR)result, textLen);
+ // Ensure result is alway zero terminated in case either syscall failed
+ if (converted == 0) {
+ reportWindowsError("convert UTF8 to UNICODE");
+ result[0] = L'\0';
+ }
+ return result;
+}
+
+void ShowMenu(HWND hWnd) {
+ POINT p;
+ if (0 == GetCursorPos(&p)) {
+ reportWindowsError("get tray menu position");
+ return;
+ };
+ SetForegroundWindow(hWnd); // Win32 bug work-around
+ TrackPopupMenu(hTrayMenu, TPM_BOTTOMALIGN | TPM_LEFTALIGN, p.x, p.y, 0, hWnd, NULL);
+
+}
+
+int GetMenuItemId(int index) {
+ MENUITEMINFO menuItemInfo;
+ menuItemInfo.cbSize = sizeof(MENUITEMINFO);
+ menuItemInfo.fMask = MIIM_DATA;
+ if (0 == GetMenuItemInfo(hTrayMenu, index, TRUE, &menuItemInfo)) {
+ reportWindowsError("get menu item id");
+ return -1;
+ }
+ int *id = (int*)menuItemInfo.dwItemData;
+ if (id == NULL) {
+ return -1;
+ }
+ return *id;
+}
+
+LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
+ switch (message) {
+ case WM_MENUCOMMAND:
+ {
+ int menuId = GetMenuItemId(wParam);
+ if (menuId != -1) {
+ systray_menu_item_selected(menuId);
+ }
+ }
+ break;
+ case WM_DESTROY:
+ Shell_NotifyIcon(NIM_DELETE, &nid);
+ PostQuitMessage(0);
+ break;
+ case WM_SYSTRAY_MESSAGE:
+ switch(lParam) {
+ case WM_RBUTTONUP:
+ ShowMenu(hWnd);
+ break;
+ case WM_LBUTTONUP:
+ ShowMenu(hWnd);
+ break;
+ default:
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ };
+ break;
+ default:
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+ return 0;
+}
+
+void MyRegisterClass(HINSTANCE hInstance, TCHAR* szWindowClass) {
+ WNDCLASSEX wcex;
+
+ wcex.cbSize = sizeof(WNDCLASSEX);
+ wcex.style = CS_HREDRAW | CS_VREDRAW;
+ wcex.lpfnWndProc = WndProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = hInstance;
+ wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+ wcex.lpszMenuName = 0;
+ wcex.lpszClassName = szWindowClass;
+ wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
+
+ RegisterClassEx(&wcex);
+}
+
+HWND InitInstance(HINSTANCE hInstance, int nCmdShow, TCHAR* szWindowClass) {
+ HWND hWnd = CreateWindow(szWindowClass, TEXT(""), WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
+ if (!hWnd) {
+ return 0;
+ }
+
+ ShowWindow(hWnd, nCmdShow);
+ UpdateWindow(hWnd);
+
+ return hWnd;
+}
+
+
+BOOL createMenu() {
+ hTrayMenu = CreatePopupMenu();
+ MENUINFO menuInfo;
+ menuInfo.cbSize = sizeof(MENUINFO);
+ menuInfo.fMask = MIM_APPLYTOSUBMENUS | MIM_STYLE;
+ menuInfo.dwStyle = MNS_NOTIFYBYPOS;
+ return SetMenuInfo(hTrayMenu, &menuInfo);
+}
+
+BOOL addNotifyIcon() {
+ nid.cbSize = sizeof(NOTIFYICONDATA);
+ nid.hWnd = hWnd;
+ nid.uID = 100;
+ nid.uCallbackMessage = WM_SYSTRAY_MESSAGE;
+ nid.uFlags = NIF_MESSAGE;
+ return Shell_NotifyIcon(NIM_ADD, &nid);
+}
+
+int nativeLoop(void (*systray_ready)(), void (*_systray_menu_item_selected)(int menu_id)) {
+ systray_menu_item_selected = _systray_menu_item_selected;
+
+ HINSTANCE hInstance = GetModuleHandle(NULL);
+ TCHAR* szWindowClass = TEXT("SystrayClass");
+ MyRegisterClass(hInstance, szWindowClass);
+ hWnd = InitInstance(hInstance, FALSE, szWindowClass); // Don't show window
+ if (!hWnd) {
+ return EXIT_FAILURE;
+ }
+ if (!createMenu() || !addNotifyIcon()) {
+ return EXIT_FAILURE;
+ }
+ systray_ready();
+
+ MSG msg;
+ while (GetMessage(&msg, NULL, 0, 0)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ return EXIT_SUCCESS;
+}
+
+
+void setIcon(const char* ciconFile) {
+ wchar_t* iconFile = UTF8ToUnicode(ciconFile);
+ HICON hIcon = (HICON) LoadImage(NULL, iconFile, IMAGE_ICON, 64, 64, LR_LOADFROMFILE);
+ if (hIcon == NULL) {
+ reportWindowsError("load icon image");
+ } else {
+ nid.hIcon = hIcon;
+ nid.uFlags = NIF_ICON;
+ Shell_NotifyIcon(NIM_MODIFY, &nid);
+ }
+}
+
+void setTooltip(char* ctooltip) {
+ wchar_t* tooltip = UTF8ToUnicode(ctooltip);
+ wcsncpy_s(nid.szTip, tooltip, 64);
+ nid.uFlags = NIF_TIP;
+ Shell_NotifyIcon(NIM_MODIFY, &nid);
+ free(tooltip);
+ free(ctooltip);
+}
+
+void add_or_update_menu_item(int menuId, char* ctitle, char* ctooltip, short disabled, short checked) {
+ wchar_t* title = UTF8ToUnicode(ctitle);
+ int *id = (int *) malloc(sizeof(int));
+ if (id == NULL) {
+ printf("Unable to allocate space for id");
+ return;
+ }
+ *id = menuId;
+
+ MENUITEMINFO menuItemInfo;
+ menuItemInfo.cbSize = sizeof(MENUITEMINFO);
+ menuItemInfo.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_DATA | MIIM_STATE;
+ menuItemInfo.fType = MFT_STRING;
+ menuItemInfo.dwTypeData = title;
+ menuItemInfo.cch = wcslen(title) + 1;
+ menuItemInfo.dwItemData = (ULONG_PTR)id;
+ menuItemInfo.fState = 0;
+ if (disabled == 1) {
+ menuItemInfo.fState |= MFS_DISABLED;
+ }
+ if (checked == 1) {
+ menuItemInfo.fState |= MFS_CHECKED;
+ }
+
+ int itemCount = GetMenuItemCount(hTrayMenu);
+ int i;
+ for (i = 0; i < itemCount; i++) {
+ int id = GetMenuItemId(i);
+ if (-1 == id) {
+ continue;
+ }
+ if (menuId == id) {
+ SetMenuItemInfo(hTrayMenu, i, TRUE, &menuItemInfo);
+ break;
+ }
+ }
+ if (i == itemCount) {
+ InsertMenuItem(hTrayMenu, -1, TRUE, &menuItemInfo);
+ }
+
+ free(ctooltip);
+}
+
+void quit() {
+ PostMessage(hWnd, WM_DESTROY, 0, 0);
+} \ No newline at end of file
diff --git a/systray/systray/systray.h b/systray/systray/systray.h
new file mode 100755
index 0000000..76d0f11
--- /dev/null
+++ b/systray/systray/systray.h
@@ -0,0 +1,10 @@
+#pragma once
+
+extern "C" {
+ __declspec(dllexport) int nativeLoop(void (*systray_ready)(), void (*_systray_menu_item_selected)(int menu_id));
+
+ __declspec(dllexport) void setIcon(const char* iconFile);
+ __declspec(dllexport) void setTooltip(char* tooltip);
+ __declspec(dllexport) void add_or_update_menu_item(int menuId, char* title, char* tooltip, short disabled, short checked);
+ __declspec(dllexport) void quit();
+} \ No newline at end of file
diff --git a/systray/systray/systray.vcxproj b/systray/systray/systray.vcxproj
new file mode 100755
index 0000000..704aceb
--- /dev/null
+++ b/systray/systray/systray.vcxproj
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{7DD84108-D77F-4F51-AC68-5DD13AC1E489}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>systray</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;SYSTRAY_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;SYSTRAY_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <None Include="ReadMe.txt" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="stdafx.h" />
+ <ClInclude Include="systray.h" />
+ <ClInclude Include="targetver.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="dllmain.cpp">
+ <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</CompileAsManaged>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ </PrecompiledHeader>
+ <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</CompileAsManaged>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ </PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="stdafx.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="systray.cpp" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/systray/systray/systray.vcxproj.filters b/systray/systray/systray.vcxproj.filters
new file mode 100755
index 0000000..594e345
--- /dev/null
+++ b/systray/systray/systray.vcxproj.filters
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="ReadMe.txt" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="stdafx.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="targetver.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="systray.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="stdafx.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="systray.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="dllmain.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/systray/systray/systray.vcxproj.user b/systray/systray/systray.vcxproj.user
new file mode 100755
index 0000000..695b5c7
--- /dev/null
+++ b/systray/systray/systray.vcxproj.user
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+</Project> \ No newline at end of file
diff --git a/systray/systray/targetver.h b/systray/systray/targetver.h
new file mode 100755
index 0000000..90e767b
--- /dev/null
+++ b/systray/systray/targetver.h
@@ -0,0 +1,8 @@
+#pragma once
+
+// Including SDKDDKVer.h defines the highest available Windows platform.
+
+// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
+// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
+
+#include <SDKDDKVer.h>
diff --git a/systray_linux.c b/systray_linux.c
index 1cbebbe..83b4690 100644
--- a/systray_linux.c
+++ b/systray_linux.c
@@ -13,11 +13,11 @@ static GArray *global_temp_icon_file_names = NULL;
typedef struct {
GtkWidget *menu_item;
- char *menu_id;
+ int menu_id;
} MenuItemNode;
typedef struct {
- char* menu_id;
+ int menu_id;
char* title;
char* tooltip;
short disabled;
@@ -62,15 +62,18 @@ gboolean do_set_icon(gpointer data) {
return FALSE;
}
+void _systray_menu_item_selected(int *id) {
+ systray_menu_item_selected(*id);
+}
+
// runs in main thread, should always return FALSE to prevent gtk to execute it again
gboolean do_add_or_update_menu_item(gpointer data) {
MenuItemInfo *mii = (MenuItemInfo*)data;
GList* it;
for(it = global_menu_items; it != NULL; it = it->next) {
MenuItemNode* item = (MenuItemNode*)(it->data);
- if(strcmp(item->menu_id, mii->menu_id) == 0){
+ if(item->menu_id == mii->menu_id){
gtk_menu_item_set_label(GTK_MENU_ITEM(item->menu_item), mii->title);
- free(mii->menu_id);
break;
}
}
@@ -78,7 +81,9 @@ gboolean do_add_or_update_menu_item(gpointer data) {
// menu id doesn't exist, add new item
if(it == NULL) {
GtkWidget *menu_item = gtk_menu_item_new_with_label(mii->title);
- g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(systray_menu_item_selected), mii->menu_id);
+ int *id = malloc(sizeof(int));
+ *id = mii->menu_id;
+ g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(_systray_menu_item_selected), id);
gtk_menu_shell_append(GTK_MENU_SHELL(global_tray_menu), menu_item);
MenuItemNode* new_item = malloc(sizeof(MenuItemNode));
@@ -134,7 +139,7 @@ void setTooltip(char* ctooltip) {
free(ctooltip);
}
-void add_or_update_menu_item(char* menu_id, char* title, char* tooltip, short disabled, short checked) {
+void add_or_update_menu_item(int menu_id, char* title, char* tooltip, short disabled, short checked) {
MenuItemInfo *mii = malloc(sizeof(MenuItemInfo));
mii->menu_id = menu_id;
mii->title = title;
diff --git a/systray_nonwindows.go b/systray_nonwindows.go
new file mode 100644
index 0000000..f570b42
--- /dev/null
+++ b/systray_nonwindows.go
@@ -0,0 +1,71 @@
+// +build !windows
+
+package systray
+
+/*
+#cgo linux pkg-config: gtk+-3.0 appindicator3-0.1
+#cgo darwin CFLAGS: -DDARWIN -x objective-c -fobjc-arc
+#cgo darwin LDFLAGS: -framework Cocoa
+
+#include "systray.h"
+*/
+import "C"
+
+import (
+ "unsafe"
+)
+
+func nativeLoop() {
+ C.nativeLoop()
+}
+
+func quit() {
+ C.quit()
+}
+
+// SetIcon sets the systray icon.
+// iconBytes should be the content of .ico for windows and .ico/.jpg/.png
+// for other platforms.
+func SetIcon(iconBytes []byte) {
+ cstr := (*C.char)(unsafe.Pointer(&iconBytes[0]))
+ C.setIcon(cstr, (C.int)(len(iconBytes)))
+}
+
+// SetTitle sets the systray title, only available on Mac.
+func SetTitle(title string) {
+ C.setTitle(C.CString(title))
+}
+
+// SetTitle sets the systray tooltip to display on mouse hover of the tray icon,
+// only available on Mac and Windows.
+func SetTooltip(tooltip string) {
+ C.setTooltip(C.CString(tooltip))
+}
+
+func addOrUpdateMenuItem(item *MenuItem) {
+ var disabled C.short = 0
+ if item.disabled {
+ disabled = 1
+ }
+ var checked C.short = 0
+ if item.checked {
+ checked = 1
+ }
+ C.add_or_update_menu_item(
+ C.int(item.id),
+ C.CString(item.title),
+ C.CString(item.tooltip),
+ disabled,
+ checked,
+ )
+}
+
+//export systray_ready
+func systray_ready() {
+ systrayReady()
+}
+
+//export systray_menu_item_selected
+func systray_menu_item_selected(cId C.int) {
+ systrayMenuItemSelected(int32(cId))
+}
diff --git a/systray_windows.go b/systray_windows.go
new file mode 100644
index 0000000..9ae9520
--- /dev/null
+++ b/systray_windows.go
@@ -0,0 +1,151 @@
+package systray
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path"
+ "syscall"
+ "unsafe"
+
+ "github.com/getlantern/tarfs"
+)
+
+var (
+ iconFiles = make([]*os.File, 0)
+ dllDir = path.Join(os.Getenv("APPDATA"), "systray")
+ dllFile = path.Join(dllDir, "systray.dll")
+
+ mod = syscall.NewLazyDLL(dllFile)
+ _nativeLoop = mod.NewProc("nativeLoop")
+ _quit = mod.NewProc("quit")
+ _setIcon = mod.NewProc("setIcon")
+ _setTitle = mod.NewProc("setTitle")
+ _setTooltip = mod.NewProc("setTooltip")
+ _add_or_update_menu_item = mod.NewProc("add_or_update_menu_item")
+)
+
+func init() {
+ // Write DLL to file
+ fs, err := tarfs.New(systraydll, "")
+ if err != nil {
+ panic(fmt.Errorf("Unable to open systray.dll: %v", err))
+ }
+
+ b, err := fs.Get("systray.dll")
+ if err != nil {
+ panic(fmt.Errorf("Unable to read systray.dll: %v", err))
+ }
+
+ err = os.MkdirAll(dllDir, 755)
+ if err != nil {
+ panic(fmt.Errorf("Unable to create directory %v to hold systray.dll: %v", dllDir, err))
+ }
+
+ err = ioutil.WriteFile(dllFile, b, 0644)
+ if err != nil {
+ panic(fmt.Errorf("Unable to save systray.dll to %v: %v", dllFile, err))
+ }
+}
+
+func nativeLoop() {
+ _nativeLoop.Call(
+ syscall.NewCallback(systray_ready),
+ syscall.NewCallback(systray_menu_item_selected))
+}
+
+func quit() {
+ _quit.Call()
+ for _, f := range iconFiles {
+ err := os.Remove(f.Name())
+ if err != nil {
+ log.Debugf("Unable to delete temporary icon file %v: %v", f.Name(), err)
+ }
+ }
+}
+
+// SetIcon sets the systray icon.
+// iconBytes should be the content of .ico for windows and .ico/.jpg/.png
+// for other platforms.
+func SetIcon(iconBytes []byte) {
+ f, err := ioutil.TempFile("", "systray_temp_icon")
+ if err != nil {
+ log.Errorf("Unable to create temp icon: %v", err)
+ return
+ }
+ defer f.Close()
+ _, err = f.Write(iconBytes)
+ if err != nil {
+ log.Errorf("Unable to write icon to temp file %v: %v", f.Name(), f)
+ return
+ }
+ f.Close()
+ name, err := strPtr(f.Name())
+ if err != nil {
+ log.Errorf("Unable to convert name to string pointer: %v", err)
+ return
+ }
+ _setIcon.Call(name)
+}
+
+// SetTitle sets the systray title, only available on Mac.
+func SetTitle(title string) {
+ // do nothing
+}
+
+// SetTooltip sets the systray tooltip to display on mouse hover of the tray icon,
+// only available on Mac and Windows.
+func SetTooltip(tooltip string) {
+ t, err := strPtr(tooltip)
+ if err != nil {
+ log.Errorf("Unable to convert tooltip to string pointer: %v", err)
+ return
+ }
+ _setTooltip.Call(t)
+}
+
+func addOrUpdateMenuItem(item *MenuItem) {
+ var disabled = 0
+ if item.disabled {
+ disabled = 1
+ }
+ var checked = 0
+ if item.checked {
+ checked = 1
+ }
+ title, err := strPtr(item.title)
+ if err != nil {
+ log.Errorf("Unable to convert title to string pointer: %v", err)
+ return
+ }
+ tooltip, err := strPtr(item.tooltip)
+ if err != nil {
+ log.Errorf("Unable to convert tooltip to string pointer: %v", err)
+ return
+ }
+ _add_or_update_menu_item.Call(
+ uintptr(item.id),
+ title,
+ tooltip,
+ uintptr(disabled),
+ uintptr(checked),
+ )
+}
+
+func strPtr(s string) (uintptr, error) {
+ bp, err := syscall.BytePtrFromString(s)
+ if err != nil {
+ return 0, err
+ }
+ return uintptr(unsafe.Pointer(bp)), nil
+}
+
+func systray_ready() uintptr {
+ systrayReady()
+ return 0
+}
+
+func systray_menu_item_selected(id uintptr) uintptr {
+ systrayMenuItemSelected(int32(id))
+ return 0
+}
diff --git a/systraydll_windows.go b/systraydll_windows.go
new file mode 100644
index 0000000..bf3161c
--- /dev/null
+++ b/systraydll_windows.go
@@ -0,0 +1,3 @@
+package systray
+
+var systraydll = []byte("\x73\x79\x73\x74\x72\x61\x79\x2e\x64\x6c\x6c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x30\x30\x30\x30\x30\x30\x30\x00\x30\x30\x30\x30\x30\x30\x30\x00\x30\x30\x30\x30\x30\x30\x30\x00\x30\x30\x30\x30\x30\x30\x32\x33\x30\x30\x30\x00\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x00\x30\x31\x31\x33\x31\x35\x00\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x75\x73\x74\x61\x72\x00\x30\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x30\x30\x30\x30\x30\x30\x30\x00\x30\x30\x30\x30\x30\x30\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x4d\x5a\x90\x00\x03\x00\x00\x00\x04\x00\x00\x00\xff\xff\x00\x00\xb8\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8\x00\x00\x00\x0e\x1f\xba\x0e\x00\xb4\x09\xcd\x21\xb8\x01\x4c\xcd\x21\x54\x68\x69\x73\x20\x70\x72\x6f\x67\x72\x61\x6d\x20\x63\x61\x6e\x6e\x6f\x74\x20\x62\x65\x20\x72\x75\x6e\x20\x69\x6e\x20\x44\x4f\x53\x20\x6d\x6f\x64\x65\x2e\x0d\x0d\x0a\x24\x00\x00\x00\x00\x00\x00\x00\x74\x8f\x66\x67\x30\xee\x08\x34\x30\xee\x08\x34\x30\xee\x08\x34\x5f\x98\x94\x34\x32\xee\x08\x34\x5f\x98\x96\x34\x31\xee\x08\x34\x5f\x98\xa2\x34\x3b\xee\x08\x34\x5f\x98\xa3\x34\x32\xee\x08\x34\x39\x96\x9b\x34\x37\xee\x08\x34\x30\xee\x09\x34\x0c\xee\x08\x34\x5f\x98\xa7\x34\x33\xee\x08\x34\x5f\x98\x93\x34\x31\xee\x08\x34\x5f\x98\x95\x34\x31\xee\x08\x34\x52\x69\x63\x68\x30\xee\x08\x34\x00\x00\x00\x00\x00\x00\x00\x00\x50\x45\x00\x00\x4c\x01\x05\x00\xba\x85\xdd\x54\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x02\x21\x0b\x01\x0a\x00\x00\x10\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\xf0\x19\x00\x00\x00\x10\x00\x00\x00\x20\x00\x00\x00\x00\x00\x10\x00\x10\x00\x00\x00\x02\x00\x00\x05\x00\x01\x00\x00\x00\x00\x00\x05\x00\x01\x00\x00\x00\x00\x00\x00\x60\x00\x00\x00\x04\x00\x00\xb9\xfd\x00\x00\x02\x00\x40\x01\x00\x00\x10\x00\x00\x10\x00\x00\x00\x00\x10\x00\x00\x10\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x10\x29\x00\x00\xa1\x00\x00\x00\x4c\x23\x00\x00\x64\x00\x00\x00\x00\x40\x00\x00\xb4\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x50\x00\x00\xd4\x01\x00\x00\x20\x21\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf8\x21\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x2e\x74\x65\x78\x74\x00\x00\x00\xde\x0e\x00\x00\x00\x10\x00\x00\x00\x10\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x60\x2e\x72\x64\x61\x74\x61\x00\x00\xb1\x09\x00\x00\x00\x20\x00\x00\x00\x0a\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x40\x2e\x64\x61\x74\x61\x00\x00\x00\x28\x07\x00\x00\x00\x30\x00\x00\x00\x02\x00\x00\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\xc0\x2e\x72\x73\x72\x63\x00\x00\x00\xb4\x01\x00\x00\x00\x40\x00\x00\x00\x02\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x40\x2e\x72\x65\x6c\x6f\x63\x00\x00\x6e\x02\x00\x00\x00\x50\x00\x00\x00\x04\x00\x00\x00\x22\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x42\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb8\x01\x00\x00\x00\xc2\x0c\x00\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\x56\x57\x6a\x00\x6a\x00\x6a\xff\x53\x6a\x00\x68\xe9\xfd\x00\x00\xff\x15\x08\x20\x00\x10\x8b\xf0\x8d\x46\x01\x6a\x02\x50\xff\x15\x78\x20\x00\x10\x83\xc4\x08\x56\x8b\xf8\x57\x6a\xff\x53\x6a\x00\x68\xe9\xfd\x00\x00\xff\x15\x08\x20\x00\x10\x85\xc0\x75\x39\xff\x15\x00\x20\x00\x10\x6a\x00\x6a\x00\x6a\x00\x6a\x00\x8b\xf0\x56\x6a\x00\x68\x00\x31\x00\x00\xff\x15\x04\x20\x00\x10\x6a\x00\x56\x68\x64\x21\x00\x10\x68\x48\x21\x00\x10\xff\x15\x74\x20\x00\x10\x83\xc4\x10\x33\xc9\x66\x89\x0f\x8b\xc7\x5f\x5e\xc3\xcc\xcc\xcc\x55\x8b\xec\x83\xec\x0c\x56\x8b\xf0\x8d\x45\xf8\x50\xff\x15\xf4\x20\x00\x10\x85\xc0\x75\x39\xff\x15\x00\x20\x00\x10\x6a\x00\x6a\x00\x6a\x00\x6a\x00\x8b\xf0\x56\x6a\x00\x68\x00\x31\x00\x00\xff\x15\x04\x20\x00\x10\x6a\x00\x56\x68\x7c\x21\x00\x10\x68\x48\x21\x00\x10\xff\x15\x74\x20\x00\x10\x83\xc4\x10\x5e\x8b\xe5\x5d\xc3\x56\xff\x15\xf0\x20\x00\x10\x8b\x4d\xfc\x8b\x55\xf8\xa1\x50\x33\x00\x10\x6a\x00\x56\x6a\x00\x51\x52\x6a\x20\x50\xff\x15\xec\x20\x00\x10\x5e\x8b\xe5\x5d\xc3\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\x55\x8b\xec\x83\xec\x34\x8b\x15\x50\x33\x00\x10\x56\x8d\x45\xd0\x50\x6a\x01\x51\x52\xc7\x45\xd0\x30\x00\x00\x00\xc7\x45\xd4\x20\x00\x00\x00\xff\x15\xe8\x20\x00\x10\x85\xc0\x75\x3c\xff\x15\x00\x20\x00\x10\x6a\x00\x6a\x00\x6a\x00\x6a\x00\x8b\xf0\x56\x6a\x00\x68\x00\x31\x00\x00\xff\x15\x04\x20\x00\x10\x6a\x00\x56\x68\x94\x21\x00\x10\x68\x48\x21\x00\x10\xff\x15\x74\x20\x00\x10\x83\xc4\x10\x83\xc8\xff\x5e\x8b\xe5\x5d\xc3\x8b\x45\xf0\x85\xc0\x74\xf1\x8b\x00\x5e\x8b\xe5\x5d\xc3\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\x55\x8b\xec\x83\xe4\xf8\x8b\x4d\x0c\x8b\xc1\x83\xe8\x02\x0f\x84\x81\x00\x00\x00\x2d\x24\x01\x00\x00\x74\x5b\x2d\xdb\x02\x00\x00\x74\x19\x8b\x45\x14\x8b\x55\x10\x50\x8b\x45\x08\x52\x51\x50\xff\x15\xe0\x20\x00\x10\x8b\xe5\x5d\xc2\x10\x00\x8b\x4d\x14\x8b\xc1\x2d\x02\x02\x00\x00\x74\x1f\x83\xe8\x03\x74\x1a\x8b\x55\x08\x51\x8b\x4d\x10\x51\x68\x01\x04\x00\x00\x52\xff\x15\xe0\x20\x00\x10\x8b\xe5\x5d\xc2\x10\x00\x8b\x45\x08\xe8\x92\xfe\xff\xff\x33\xc0\x8b\xe5\x5d\xc2\x10\x00\x8b\x4d\x10\xe8\x02\xff\xff\xff\x83\xf8\xff\x74\x27\x50\xff\x15\x4c\x33\x00\x10\x83\xc4\x04\x33\xc0\x8b\xe5\x5d\xc2\x10\x00\x68\x58\x33\x00\x10\x6a\x02\xff\x15\x9c\x20\x00\x10\x6a\x00\xff\x15\xe4\x20\x00\x10\x33\xc0\x8b\xe5\x5d\xc2\x10\x00\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\x55\x8b\xec\x83\xec\x30\x56\x8b\x35\xdc\x20\x00\x10\x68\x00\x7f\x00\x00\x6a\x00\xc7\x45\xd0\x30\x00\x00\x00\xc7\x45\xd4\x03\x00\x00\x00\xc7\x45\xd8\x90\x11\x00\x10\xc7\x45\xdc\x00\x00\x00\x00\xc7\x45\xe0\x00\x00\x00\x00\x89\x45\xe4\xff\xd6\x68\x00\x7f\x00\x00\x6a\x00\x89\x45\xe8\xff\x15\xd8\x20\x00\x10\x68\x00\x7f\x00\x00\x6a\x00\x89\x45\xec\xc7\x45\xf0\x06\x00\x00\x00\xc7\x45\xf4\x00\x00\x00\x00\xc7\x45\xf8\xac\x21\x00\x10\xff\xd6\x8d\x4d\xd0\x51\x89\x45\xfc\xff\x15\xd4\x20\x00\x10\x5e\x8b\xe5\x5d\xc3\xcc\x55\x8b\xec\x8b\x45\x0c\x83\xec\x38\x56\x6a\x00\xa3\x4c\x33\x00\x10\xff\x15\x0c\x20\x00\x10\x8b\xf0\xe8\x62\xff\xff\xff\x6a\x00\x56\x6a\x00\x6a\x00\x6a\x00\x68\x00\x00\x00\x80\x6a\x00\x68\x00\x00\x00\x80\x68\x00\x00\xcf\x00\x68\xa8\x21\x00\x10\x68\xac\x21\x00\x10\x6a\x00\xff\x15\xd0\x20\x00\x10\x8b\xf0\x85\xf6\x74\x10\x6a\x00\x56\xff\x15\xcc\x20\x00\x10\x56\xff\x15\xc8\x20\x00\x10\x89\x35\x54\x33\x00\x10\x85\xf6\x0f\x84\xc7\x00\x00\x00\xff\x15\xc4\x20\x00\x10\x8d\x4d\xe4\x51\x50\xa3\x50\x33\x00\x10\xc7\x45\xe4\x1c\x00\x00\x00\xc7\x45\xe8\x10\x00\x00\x80\xc7\x45\xec\x00\x00\x00\x08\xff\x15\xc0\x20\x00\x10\x85\xc0\x0f\x84\x94\x00\x00\x00\x8b\x15\x54\x33\x00\x10\x68\x58\x33\x00\x10\x6a\x00\xc7\x05\x58\x33\x00\x10\xbc\x03\x00\x00\x89\x15\x5c\x33\x00\x10\xc7\x05\x60\x33\x00\x10\x64\x00\x00\x00\xc7\x05\x68\x33\x00\x10\x01\x04\x00\x00\xc7\x05\x64\x33\x00\x10\x01\x00\x00\x00\xff\x15\x9c\x20\x00\x10\x85\xc0\x74\x4f\xff\x55\x08\x8b\x35\xa4\x20\x00\x10\x6a\x00\x6a\x00\x6a\x00\x8d\x45\xc8\x50\xff\xd6\x85\xc0\x74\x2f\x53\x8b\x1d\xbc\x20\x00\x10\x57\x8b\x3d\xf8\x20\x00\x10\x8d\x49\x00\x8d\x4d\xc8\x51\xff\xd7\x8d\x55\xc8\x52\xff\xd3\x6a\x00\x6a\x00\x6a\x00\x8d\x45\xc8\x50\xff\xd6\x85\xc0\x75\xe4\x5f\x5b\x33\xc0\x5e\x8b\xe5\x5d\xc3\xb8\x01\x00\x00\x00\x5e\x8b\xe5\x5d\xc3\xcc\x55\x8b\xec\x53\x8b\x5d\x08\xe8\xf4\xfb\xff\xff\x6a\x10\x6a\x40\x6a\x40\x6a\x01\x50\x6a\x00\xff\x15\xb8\x20\x00\x10\x5b\x85\xc0\x75\x38\x56\xff\x15\x00\x20\x00\x10\x6a\x00\x6a\x00\x6a\x00\x6a\x00\x8b\xf0\x56\x6a\x00\x68\x00\x31\x00\x00\xff\x15\x04\x20\x00\x10\x6a\x00\x56\x68\xc8\x21\x00\x10\x68\x48\x21\x00\x10\xff\x15\x74\x20\x00\x10\x83\xc4\x10\x5e\x5d\xc3\x68\x58\x33\x00\x10\x6a\x01\xa3\x6c\x33\x00\x10\xc7\x05\x64\x33\x00\x10\x02\x00\x00\x00\xff\x15\x9c\x20\x00\x10\x5d\xc3\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\x55\x8b\xec\x53\x8b\x5d\x08\x56\xe8\x73\xfb\xff\xff\x6a\x40\x8b\xf0\x56\x68\x80\x00\x00\x00\x68\x70\x33\x00\x10\xff\x15\x84\x20\x00\x10\x83\xc4\x10\x68\x58\x33\x00\x10\x6a\x01\xc7\x05\x64\x33\x00\x10\x04\x00\x00\x00\xff\x15\x9c\x20\x00\x10\x56\x8b\x35\x68\x20\x00\x10\xff\xd6\x53\xff\xd6\x83\xc4\x08\x5e\x5b\x5d\xc3\xcc\x55\x8b\xec\x83\xe4\xf8\x83\xec\x64\x53\x8b\x5d\x0c\x56\x57\xe8\x1c\xfb\xff\xff\x6a\x04\x8b\xf0\xff\x15\x80\x20\x00\x10\x33\xff\x83\xc4\x04\x3b\xc7\x75\x15\x68\xd8\x21\x00\x10\xff\x15\x74\x20\x00\x10\x83\xc4\x04\x5f\x5e\x5b\x8b\xe5\x5d\xc3\x8b\x4d\x08\x89\x08\x8b\xce\x89\x74\x24\x34\xc7\x44\x24\x10\x30\x00\x00\x00\xc7\x44\x24\x14\x61\x01\x00\x00\x89\x7c\x24\x18\x8d\x71\x02\x8b\xff\x66\x8b\x11\x83\xc1\x02\x66\x3b\xd7\x75\xf5\x2b\xce\xd1\xf9\x89\x44\x24\x30\x41\xb8\x01\x00\x00\x00\x89\x4c\x24\x38\x89\x7c\x24\x1c\x66\x39\x45\x14\x75\x08\xc7\x44\x24\x1c\x03\x00\x00\x00\x66\x39\x45\x18\x75\x05\x83\x4c\x24\x1c\x08\x8b\x15\x50\x33\x00\x10\x52\xff\x15\xb4\x20\x00\x10\x8b\xf0\x89\x74\x24\x0c\x3b\xfe\x0f\x8d\x9b\x00\x00\x00\x8b\x1d\x74\x20\x00\x10\xeb\x03\x8d\x49\x00\x8b\x0d\x50\x33\x00\x10\x8d\x44\x24\x40\x50\x6a\x01\x57\x51\xc7\x44\x24\x50\x30\x00\x00\x00\xc7\x44\x24\x54\x20\x00\x00\x00\xff\x15\xe8\x20\x00\x10\x85\xc0\x75\x36\xff\x15\x00\x20\x00\x10\x6a\x00\x6a\x00\x6a\x00\x6a\x00\x8b\xf0\x56\x6a\x00\x68\x00\x31\x00\x00\xff\x15\x04\x20\x00\x10\x6a\x00\x56\x68\x94\x21\x00\x10\x68\x48\x21\x00\x10\xff\xd3\x8b\x74\x24\x1c\x83\xc4\x10\xeb\x14\x8b\x44\x24\x60\x85\xc0\x74\x0c\x8b\x00\x83\xf8\xff\x74\x05\x39\x45\x08\x74\x07\x47\x3b\xfe\x7c\x88\xeb\x14\xa1\x50\x33\x00\x10\x8d\x54\x24\x10\x52\x6a\x01\x57\x50\xff\x15\xb0\x20\x00\x10\x3b\xfe\x75\x16\x8b\x15\x50\x33\x00\x10\x8d\x4c\x24\x10\x51\x6a\x01\x6a\xff\x52\xff\x15\xac\x20\x00\x10\x8b\x45\x10\x50\xff\x15\x68\x20\x00\x10\x83\xc4\x04\x5f\x5e\x5b\x8b\xe5\x5d\xc3\xcc\xcc\xcc\xcc\xa1\x54\x33\x00\x10\x6a\x00\x6a\x00\x6a\x02\x50\xff\x15\xa8\x20\x00\x10\xc3\x3b\x0d\x00\x30\x00\x10\x75\x02\xf3\xc3\xe9\x91\x03\x00\x00\x8b\xff\x56\x68\x80\x00\x00\x00\xff\x15\x88\x20\x00\x10\x59\x8b\xf0\x56\xff\x15\x44\x20\x00\x10\xa3\x20\x37\x00\x10\xa3\x1c\x37\x00\x10\x85\xf6\x75\x05\x33\xc0\x40\x5e\xc3\x83\x26\x00\xe8\x28\x05\x00\x00\x68\x03\x1c\x00\x10\xe8\x07\x05\x00\x00\xc7\x04\x24\x19\x1b\x00\x10\xe8\xfb\x04\x00\x00\x59\x33\xc0\x5e\xc3\x8b\xff\x55\x8b\xec\x51\x51\x53\x33\xc0\x56\x57\x39\x45\x0c\x75\x32\x39\x05\x10\x30\x00\x10\x7e\x23\x64\xa1\x18\x00\x00\x00\xff\x0d\x10\x30\x00\x10\x8b\x58\x04\x83\x65\xfc\x00\x8b\x35\x34\x20\x00\x10\xbf\x18\x37\x00\x10\xe9\xea\x00\x00\x00\x33\xc0\xe9\xc0\x01\x00\x00\x83\x7d\x0c\x01\x0f\x85\xb3\x01\x00\x00\x64\x8b\x0d\x18\x00\x00\x00\x8b\x59\x04\x8b\x35\x34\x20\x00\x10\x89\x45\x0c\x50\xbf\x18\x37\x00\x10\xeb\x11\x3b\xc3\x74\x17\x68\xe8\x03\x00\x00\xff\x15\x38\x20\x00\x10\x6a\x00\x53\x57\xff\xd6\x85\xc0\x75\xe7\xeb\x07\xc7\x45\x0c\x01\x00\x00\x00\xa1\x14\x37\x00\x10\x6a\x02\x5e\x85\xc0\x74\x09\x6a\x1f\xe8\x1b\x06\x00\x00\xeb\x39\x68\x10\x21\x00\x10\x68\x08\x21\x00\x10\xc7\x05\x14\x37\x00\x10\x01\x00\x00\x00\xe8\xfa\x05\x00\x00\x59\x59\x85\xc0\x0f\x85\x7a\xff\xff\xff\x68\x04\x21\x00\x10\x68\x00\x21\x00\x10\xe8\xdb\x05\x00\x00\x59\x89\x35\x14\x37\x00\x10\x33\xdb\x59\x39\x5d\x0c\x75\x08\x53\x57\xff\x15\x3c\x20\x00\x10\x39\x1d\x24\x37\x00\x10\x74\x1c\x68\x24\x37\x00\x10\xe8\xf6\x04\x00\x00\x59\x85\xc0\x74\x0d\xff\x75\x10\x56\xff\x75\x08\xff\x15\x24\x37\x00\x10\xff\x05\x10\x30\x00\x10\xe9\xe9\x00\x00\x00\x3b\xc3\x74\x17\x68\xe8\x03\x00\x00\xff\x15\x38\x20\x00\x10\x6a\x00\x53\x57\xff\xd6\x85\xc0\x75\xe7\xeb\x07\xc7\x45\xfc\x01\x00\x00\x00\xa1\x14\x37\x00\x10\x83\xf8\x02\x74\x0d\x6a\x1f\xe8\x6e\x05\x00\x00\x59\xe9\xb0\x00\x00\x00\xff\x35\x20\x37\x00\x10\x8b\x35\x40\x20\x00\x10\xff\xd6\x89\x45\x0c\x85\xc0\x0f\x84\x83\x00\x00\x00\xff\x35\x1c\x37\x00\x10\xff\xd6\x8b\xd8\x8b\x45\x0c\x89\x45\x10\x89\x5d\x08\x83\xeb\x04\x3b\x5d\x0c\x72\x4e\x83\x3b\x00\x74\xf3\xff\x15\x8c\x20\x00\x10\x39\x03\x74\xe9\xff\x33\xff\xd6\x89\x45\xf8\xff\x15\x8c\x20\x00\x10\x89\x03\xff\x55\xf8\xff\x35\x20\x37\x00\x10\xff\xd6\xff\x35\x1c\x37\x00\x10\x89\x45\xf8\xff\xd6\x8b\x4d\xf8\x39\x4d\x10\x75\x05\x39\x45\x08\x74\xb7\x89\x4d\x10\x89\x4d\x0c\x89\x45\x08\x8b\xd8\xeb\xaa\xff\x75\x0c\xff\x15\x68\x20\x00\x10\x59\xff\x15\x8c\x20\x00\x10\xa3\x1c\x37\x00\x10\xa3\x20\x37\x00\x10\x33\xc0\xa3\x14\x37\x00\x10\x39\x45\xfc\x75\x08\x50\x57\xff\x15\x3c\x20\x00\x10\x33\xc0\x40\x5f\x5e\x5b\xc9\xc2\x0c\x00\x6a\x10\x68\xe8\x22\x00\x10\xe8\xba\x04\x00\x00\x8b\xf9\x8b\xf2\x8b\x5d\x08\x33\xc0\x40\x89\x45\xe4\x33\xc9\x89\x4d\xfc\x89\x35\x08\x30\x00\x10\x89\x45\xfc\x3b\xf1\x75\x10\x39\x0d\x10\x30\x00\x10\x75\x08\x89\x4d\xe4\xe9\xb7\x00\x00\x00\x3b\xf0\x74\x05\x83\xfe\x02\x75\x2e\xa1\x3c\x21\x00\x10\x3b\xc1\x74\x08\x57\x56\x53\xff\xd0\x89\x45\xe4\x83\x7d\xe4\x00\x0f\x84\x93\x00\x00\x00\x57\x56\x53\xe8\x8f\xfd\xff\xff\x89\x45\xe4\x85\xc0\x0f\x84\x80\x00\x00\x00\x57\x56\x53\xe8\xac\xf6\xff\xff\x89\x45\xe4\x83\xfe\x01\x75\x24\x85\xc0\x75\x20\x57\x50\x53\xe8\x98\xf6\xff\xff\x57\x6a\x00\x53\xe8\x5f\xfd\xff\xff\xa1\x3c\x21\x00\x10\x85\xc0\x74\x06\x57\x6a\x00\x53\xff\xd0\x85\xf6\x74\x05\x83\xfe\x03\x75\x43\x57\x56\x53\xe8\x3f\xfd\xff\xff\x85\xc0\x75\x03\x21\x45\xe4\x83\x7d\xe4\x00\x74\x2e\xa1\x3c\x21\x00\x10\x85\xc0\x74\x25\x57\x56\x53\xff\xd0\x89\x45\xe4\xeb\x1b\x8b\x45\xec\x8b\x08\x8b\x09\x89\x4d\xe0\x50\x51\xe8\xcc\x03\x00\x00\x59\x59\xc3\x8b\x65\xe8\x83\x65\xe4\x00\x83\x65\xfc\x00\xc7\x45\xfc\xfe\xff\xff\xff\xe8\x09\x00\x00\x00\x8b\x45\xe4\xe8\x01\x04\x00\x00\xc3\xc7\x05\x08\x30\x00\x10\xff\xff\xff\xff\xc3\x8b\xff\x55\x8b\xec\x83\x7d\x0c\x01\x75\x05\xe8\x1e\x04\x00\x00\xff\x75\x08\x8b\x4d\x10\x8b\x55\x0c\xe8\xcc\xfe\xff\xff\x59\x5d\xc2\x0c\x00\x8b\xff\x55\x8b\xec\x81\xec\x28\x03\x00\x00\xa3\x20\x31\x00\x10\x89\x0d\x1c\x31\x00\x10\x89\x15\x18\x31\x00\x10\x89\x1d\x14\x31\x00\x10\x89\x35\x10\x31\x00\x10\x89\x3d\x0c\x31\x00\x10\x66\x8c\x15\x38\x31\x00\x10\x66\x8c\x0d\x2c\x31\x00\x10\x66\x8c\x1d\x08\x31\x00\x10\x66\x8c\x05\x04\x31\x00\x10\x66\x8c\x25\x00\x31\x00\x10\x66\x8c\x2d\xfc\x30\x00\x10\x9c\x8f\x05\x30\x31\x00\x10\x8b\x45\x00\xa3\x24\x31\x00\x10\x8b\x45\x04\xa3\x28\x31\x00\x10\x8d\x45\x08\xa3\x34\x31\x00\x10\x8b\x85\xe0\xfc\xff\xff\xc7\x05\x70\x30\x00\x10\x01\x00\x01\x00\xa1\x28\x31\x00\x10\xa3\x24\x30\x00\x10\xc7\x05\x18\x30\x00\x10\x09\x04\x00\xc0\xc7\x05\x1c\x30\x00\x10\x01\x00\x00\x00\xa1\x00\x30\x00\x10\x89\x85\xd8\xfc\xff\xff\xa1\x04\x30\x00\x10\x89\x85\xdc\xfc\xff\xff\xff\x15\x20\x20\x00\x10\xa3\x68\x30\x00\x10\x6a\x01\xe8\xda\x03\x00\x00\x59\x6a\x00\xff\x15\x24\x20\x00\x10\x68\x40\x21\x00\x10\xff\x15\x28\x20\x00\x10\x83\x3d\x68\x30\x00\x10\x00\x75\x08\x6a\x01\xe8\xb6\x03\x00\x00\x59\x68\x09\x04\x00\xc0\xff\x15\x2c\x20\x00\x10\x50\xff\x15\x30\x20\x00\x10\xc9\xc3\x68\x3c\x33\x00\x10\xe8\x9d\x03\x00\x00\x59\xc3\x6a\x14\x68\x10\x23\x00\x10\xe8\x6f\x02\x00\x00\xff\x35\x20\x37\x00\x10\x8b\x35\x40\x20\x00\x10\xff\xd6\x89\x45\xe4\x83\xf8\xff\x75\x0c\xff\x75\x08\xff\x15\x54\x20\x00\x10\x59\xeb\x64\x6a\x08\xe8\x78\x03\x00\x00\x59\x83\x65\xfc\x00\xff\x35\x20\x37\x00\x10\xff\xd6\x89\x45\xe4\xff\x35\x1c\x37\x00\x10\xff\xd6\x89\x45\xe0\x8d\x45\xe0\x50\x8d\x45\xe4\x50\xff\x75\x08\x8b\x35\x44\x20\x00\x10\xff\xd6\x50\xe8\x3e\x03\x00\x00\x83\xc4\x0c\x89\x45\xdc\xff\x75\xe4\xff\xd6\xa3\x20\x37\x00\x10\xff\x75\xe0\xff\xd6\xa3\x1c\x37\x00\x10\xc7\x45\xfc\xfe\xff\xff\xff\xe8\x09\x00\x00\x00\x8b\x45\xdc\xe8\x29\x02\x00\x00\xc3\x6a\x08\xe8\x02\x03\x00\x00\x59\xc3\x8b\xff\x55\x8b\xec\xff\x75\x08\xe8\x52\xff\xff\xff\xf7\xd8\x1b\xc0\xf7\xd8\x59\x48\x5d\xc3\x8b\xff\x56\xb8\xd8\x22\x00\x10\xbe\xd8\x22\x00\x10\x57\x8b\xf8\x3b\xc6\x73\x0f\x8b\x07\x85\xc0\x74\x02\xff\xd0\x83\xc7\x04\x3b\xfe\x72\xf1\x5f\x5e\xc3\x8b\xff\x56\xb8\xe0\x22\x00\x10\xbe\xe0\x22\x00\x10\x57\x8b\xf8\x3b\xc6\x73\x0f\x8b\x07\x85\xc0\x74\x02\xff\xd0\x83\xc7\x04\x3b\xfe\x72\xf1\x5f\x5e\xc3\xcc\xcc\xcc\xcc\xcc\xcc\xcc\x8b\xff\x55\x8b\xec\x8b\x4d\x08\xb8\x4d\x5a\x00\x00\x66\x39\x01\x74\x04\x33\xc0\x5d\xc3\x8b\x41\x3c\x03\xc1\x81\x38\x50\x45\x00\x00\x75\xef\x33\xd2\xb9\x0b\x01\x00\x00\x66\x39\x48\x18\x0f\x94\xc2\x8b\xc2\x5d\xc3\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\x8b\xff\x55\x8b\xec\x8b\x45\x08\x8b\x48\x3c\x03\xc8\x0f\xb7\x41\x14\x53\x56\x0f\xb7\x71\x06\x33\xd2\x57\x8d\x44\x08\x18\x85\xf6\x74\x1b\x8b\x7d\x0c\x8b\x48\x0c\x3b\xf9\x72\x09\x8b\x58\x08\x03\xd9\x3b\xfb\x72\x0a\x42\x83\xc0\x28\x3b\xd6\x72\xe8\x33\xc0\x5f\x5e\x5b\x5d\xc3\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\x8b\xff\x55\x8b\xec\x6a\xfe\x68\x30\x23\x00\x10\x68\xf9\x1d\x00\x10\x64\xa1\x00\x00\x00\x00\x50\x83\xec\x08\x53\x56\x57\xa1\x00\x30\x00\x10\x31\x45\xf8\x33\xc5\x50\x8d\x45\xf0\x64\xa3\x00\x00\x00\x00\x89\x65\xe8\xc7\x45\xfc\x00\x00\x00\x00\x68\x00\x00\x00\x10\xe8\x2a\xff\xff\xff\x83\xc4\x04\x85\xc0\x74\x54\x8b\x45\x08\x2d\x00\x00\x00\x10\x50\x68\x00\x00\x00\x10\xe8\x50\xff\xff\xff\x83\xc4\x08\x85\xc0\x74\x3a\x8b\x40\x24\xc1\xe8\x1f\xf7\xd0\x83\xe0\x01\xc7\x45\xfc\xfe\xff\xff\xff\x8b\x4d\xf0\x64\x89\x0d\x00\x00\x00\x00\x59\x5f\x5e\x5b\x8b\xe5\x5d\xc3\x8b\x45\xec\x8b\x08\x33\xd2\x81\x39\x05\x00\x00\xc0\x0f\x94\xc2\x8b\xc2\xc3\x8b\x65\xe8\xc7\x45\xfc\xfe\xff\xff\xff\x33\xc0\x8b\x4d\xf0\x64\x89\x0d\x00\x00\x00\x00\x59\x5f\x5e\x5b\x8b\xe5\x5d\xc3\xff\x25\x90\x20\x00\x10\xff\x25\x94\x20\x00\x10\xff\x25\x7c\x20\x00\x10\xff\x25\x70\x20\x00\x10\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\x68\xf9\x1d\x00\x10\x64\xff\x35\x00\x00\x00\x00\x8b\x44\x24\x10\x89\x6c\x24\x10\x8d\x6c\x24\x10\x2b\xe0\x53\x56\x57\xa1\x00\x30\x00\x10\x31\x45\xfc\x33\xc5\x50\x89\x65\xe8\xff\x75\xf8\x8b\x45\xfc\xc7\x45\xfc\xfe\xff\xff\xff\x89\x45\xf8\x8d\x45\xf0\x64\xa3\x00\x00\x00\x00\xc3\x8b\x4d\xf0\x64\x89\x0d\x00\x00\x00\x00\x59\x5f\x5f\x5e\x5b\x8b\xe5\x5d\x51\xc3\x8b\xff\x55\x8b\xec\xff\x75\x14\xff\x75\x10\xff\x75\x0c\xff\x75\x08\x68\x73\x16\x00\x10\x68\x00\x30\x00\x10\xe8\xbf\x00\x00\x00\x83\xc4\x18\x5d\xc3\x8b\xff\x55\x8b\xec\x83\xec\x10\xa1\x00\x30\x00\x10\x83\x65\xf8\x00\x83\x65\xfc\x00\x53\x57\xbf\x4e\xe6\x40\xbb\xbb\x00\x00\xff\xff\x3b\xc7\x74\x0d\x85\xc3\x74\x09\xf7\xd0\xa3\x04\x30\x00\x10\xeb\x65\x56\x8d\x45\xf8\x50\xff\x15\x48\x20\x00\x10\x8b\x75\xfc\x33\x75\xf8\xff\x15\x10\x20\x00\x10\x33\xf0\xff\x15\x14\x20\x00\x10\x33\xf0\xff\x15\x18\x20\x00\x10\x33\xf0\x8d\x45\xf0\x50\xff\x15\x1c\x20\x00\x10\x8b\x45\xf4\x33\x45\xf0\x33\xf0\x3b\xf7\x75\x07\xbe\x4f\xe6\x40\xbb\xeb\x10\x85\xf3\x75\x0c\x8b\xc6\x0d\x11\x47\x00\x00\xc1\xe0\x10\x0b\xf0\x89\x35\x00\x30\x00\x10\xf7\xd6\x89\x35\x04\x30\x00\x10\x5e\x5f\x5b\xc9\xc3\xcc\xff\x25\x6c\x20\x00\x10\xff\x25\x64\x20\x00\x10\xff\x25\x60\x20\x00\x10\xff\x25\x5c\x20\x00\x10\xff\x25\x58\x20\x00\x10\xff\x25\x50\x20\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb0\x24\x00\x00\xc0\x24\x00\x00\xd2\x24\x00\x00\xe8\x24\x00\x00\xda\x28\x00\x00\xc4\x28\x00\x00\xb4\x28\x00\x00\x9a\x28\x00\x00\x86\x28\x00\x00\x68\x28\x00\x00\x4c\x28\x00\x00\x38\x28\x00\x00\x24\x28\x00\x00\x06\x28\x00\x00\xfe\x27\x00\x00\xe8\x27\x00\x00\xd8\x27\x00\x00\xc8\x27\x00\x00\xf0\x28\x00\x00\x00\x00\x00\x00\xae\x27\x00\x00\xa4\x27\x00\x00\x9c\x27\x00\x00\x8e\x27\x00\x00\x84\x27\x00\x00\x60\x27\x00\x00\xc6\x26\x00\x00\x4a\x27\x00\x00\x38\x27\x00\x00\xb2\x26\x00\x00\xbc\x26\x00\x00\x2a\x27\x00\x00\xce\x26\x00\x00\xd8\x26\x00\x00\xf2\x26\x00\x00\x00\x27\x00\x00\x10\x27\x00\x00\x1c\x27\x00\x00\x00\x00\x00\x00\x92\x26\x00\x00\x00\x00\x00\x00\xf8\x25\x00\x00\x76\x26\x00\x00\x64\x26\x00\x00\x50\x26\x00\x00\x3c\x26\x00\x00\x2e\x26\x00\x00\x1a\x26\x00\x00\xea\x25\x00\x00\xd8\x25\x00\x00\xc8\x25\x00\x00\xba\x25\x00\x00\xa8\x25\x00\x00\x94\x25\x00\x00\x86\x25\x00\x00\x7a\x25\x00\x00\x68\x25\x00\x00\x56\x25\x00\x00\x42\x25\x00\x00\x30\x25\x00\x00\x1a\x25\x00\x00\x0a\x25\x00\x00\x06\x26\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x82\x16\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xba\x85\xdd\x54\x00\x00\x00\x00\x02\x00\x00\x00\x85\x00\x00\x00\x40\x22\x00\x00\x40\x16\x00\x00\x00\x00\x00\x00\x18\x30\x00\x10\x70\x30\x00\x10\x53\x79\x73\x74\x72\x61\x79\x20\x65\x72\x72\x6f\x72\x20\x25\x73\x3a\x20\x25\x64\x20\x25\x73\x0a\x00\x00\x00\x00\x63\x6f\x6e\x76\x65\x72\x74\x20\x55\x54\x46\x38\x20\x74\x6f\x20\x55\x4e\x49\x43\x4f\x44\x45\x00\x67\x65\x74\x20\x74\x72\x61\x79\x20\x6d\x65\x6e\x75\x20\x70\x6f\x73\x69\x74\x69\x6f\x6e\x00\x00\x67\x65\x74\x20\x6d\x65\x6e\x75\x20\x69\x74\x65\x6d\x20\x69\x64\x00\x00\x00\x00\x00\x00\x00\x00\x53\x00\x79\x00\x73\x00\x74\x00\x72\x00\x61\x00\x79\x00\x43\x00\x6c\x00\x61\x00\x73\x00\x73\x00\x00\x00\x00\x00\x6c\x6f\x61\x64\x20\x69\x63\x6f\x6e\x20\x69\x6d\x61\x67\x65\x00\x55\x6e\x61\x62\x6c\x65\x20\x74\x6f\x20\x61\x6c\x6c\x6f\x63\x61\x74\x65\x20\x73\x70\x61\x63\x65\x20\x66\x6f\x72\x20\x69\x64\x00\x48\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x30\x00\x10\xd0\x22\x00\x10\x01\x00\x00\x00\x52\x53\x44\x53\xde\x0d\xf5\x5e\x53\xf4\xb2\x48\xa1\x4b\x12\xb9\x0c\x85\xb7\x09\x16\x00\x00\x00\x43\x3a\x5c\x44\x6f\x63\x75\x6d\x65\x6e\x74\x73\x20\x61\x6e\x64\x20\x53\x65\x74\x74\x69\x6e\x67\x73\x5c\x41\x64\x6d\x69\x6e\x69\x73\x74\x72\x61\x74\x6f\x72\x5c\x67\x6f\x63\x6f\x64\x65\x5c\x73\x72\x63\x5c\x67\x69\x74\x68\x75\x62\x2e\x63\x6f\x6d\x5c\x67\x65\x74\x6c\x61\x6e\x74\x65\x72\x6e\x5c\x73\x79\x73\x74\x72\x61\x79\x5c\x73\x79\x73\x74\x72\x61\x79\x5c\x52\x65\x6c\x65\x61\x73\x65\x5c\x73\x79\x73\x74\x72\x61\x79\x2e\x70\x64\x62\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf9\x1d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe\xff\xff\xff\x00\x00\x00\x00\xd0\xff\xff\xff\x00\x00\x00\x00\xfe\xff\xff\xff\x00\x00\x00\x00\xe5\x19\x00\x10\x00\x00\x00\x00\xb1\x19\x00\x10\xc5\x19\x00\x10\xfe\xff\xff\xff\x00\x00\x00\x00\xcc\xff\xff\xff\x00\x00\x00\x00\xfe\xff\xff\xff\x00\x00\x00\x00\xbd\x1b\x00\x10\x00\x00\x00\x00\xfe\xff\xff\xff\x00\x00\x00\x00\xd8\xff\xff\xff\x00\x00\x00\x00\xfe\xff\xff\xff\x4b\x1d\x00\x10\x5e\x1d\x00\x10\xb0\x23\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfc\x24\x00\x00\x00\x20\x00\x00\x54\x24\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x86\x26\x00\x00\xa4\x20\x00\x00\x4c\x24\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6\x26\x00\x00\x9c\x20\x00\x00\x00\x24\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4\x26\x00\x00\x50\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb0\x24\x00\x00\xc0\x24\x00\x00\xd2\x24\x00\x00\xe8\x24\x00\x00\xda\x28\x00\x00\xc4\x28\x00\x00\xb4\x28\x00\x00\x9a\x28\x00\x00\x86\x28\x00\x00\x68\x28\x00\x00\x4c\x28\x00\x00\x38\x28\x00\x00\x24\x28\x00\x00\x06\x28\x00\x00\xfe\x27\x00\x00\xe8\x27\x00\x00\xd8\x27\x00\x00\xc8\x27\x00\x00\xf0\x28\x00\x00\x00\x00\x00\x00\xae\x27\x00\x00\xa4\x27\x00\x00\x9c\x27\x00\x00\x8e\x27\x00\x00\x84\x27\x00\x00\x60\x27\x00\x00\xc6\x26\x00\x00\x4a\x27\x00\x00\x38\x27\x00\x00\xb2\x26\x00\x00\xbc\x26\x00\x00\x2a\x27\x00\x00\xce\x26\x00\x00\xd8\x26\x00\x00\xf2\x26\x00\x00\x00\x27\x00\x00\x10\x27\x00\x00\x1c\x27\x00\x00\x00\x00\x00\x00\x92\x26\x00\x00\x00\x00\x00\x00\xf8\x25\x00\x00\x76\x26\x00\x00\x64\x26\x00\x00\x50\x26\x00\x00\x3c\x26\x00\x00\x2e\x26\x00\x00\x1a\x26\x00\x00\xea\x25\x00\x00\xd8\x25\x00\x00\xc8\x25\x00\x00\xba\x25\x00\x00\xa8\x25\x00\x00\x94\x25\x00\x00\x86\x25\x00\x00\x7a\x25\x00\x00\x68\x25\x00\x00\x56\x25\x00\x00\x42\x25\x00\x00\x30\x25\x00\x00\x1a\x25\x00\x00\x0a\x25\x00\x00\x06\x26\x00\x00\x00\x00\x00\x00\x02\x02\x47\x65\x74\x4c\x61\x73\x74\x45\x72\x72\x6f\x72\x00\x00\x5e\x01\x46\x6f\x72\x6d\x61\x74\x4d\x65\x73\x73\x61\x67\x65\x57\x00\x00\x67\x03\x4d\x75\x6c\x74\x69\x42\x79\x74\x65\x54\x6f\x57\x69\x64\x65\x43\x68\x61\x72\x00\x18\x02\x47\x65\x74\x4d\x6f\x64\x75\x6c\x65\x48\x61\x6e\x64\x6c\x65\x57\x00\x00\x4b\x45\x52\x4e\x45\x4c\x33\x32\x2e\x64\x6c\x6c\x00\x00\x20\x01\x47\x65\x74\x43\x75\x72\x73\x6f\x72\x50\x6f\x73\x00\x00\x93\x02\x53\x65\x74\x46\x6f\x72\x65\x67\x72\x6f\x75\x6e\x64\x57\x69\x6e\x64\x6f\x77\x00\xf6\x02\x54\x72\x61\x63\x6b\x50\x6f\x70\x75\x70\x4d\x65\x6e\x75\x00\x00\x54\x01\x47\x65\x74\x4d\x65\x6e\x75\x49\x74\x65\x6d\x49\x6e\x66\x6f\x57\x00\x00\x37\x02\x50\x6f\x73\x74\x51\x75\x69\x74\x4d\x65\x73\x73\x61\x67\x65\x00\x9c\x00\x44\x65\x66\x57\x69\x6e\x64\x6f\x77\x50\x72\x6f\x63\x57\x00\x00\xed\x01\x4c\x6f\x61\x64\x49\x63\x6f\x6e\x57\x00\xeb\x01\x4c\x6f\x61\x64\x43\x75\x72\x73\x6f\x72\x57\x00\x4d\x02\x52\x65\x67\x69\x73\x74\x65\x72\x43\x6c\x61\x73\x73\x45\x78\x57\x00\x00\x6e\x00\x43\x72\x65\x61\x74\x65\x57\x69\x6e\x64\x6f\x77\x45\x78\x57\x00\xdf\x02\x53\x68\x6f\x77\x57\x69\x6e\x64\x6f\x77\x00\x00\x11\x03\x55\x70\x64\x61\x74\x65\x57\x69\x6e\x64\x6f\x77\x00\x00\x6b\x00\x43\x72\x65\x61\x74\x65\x50\x6f\x70\x75\x70\x4d\x65\x6e\x75\x00\x9f\x02\x53\x65\x74\x4d\x65\x6e\x75\x49\x6e\x66\x6f\x00\x5d\x01\x47\x65\x74\x4d\x65\x73\x73\x61\x67\x65\x57\x00\xfc\x02\x54\x72\x61\x6e\x73\x6c\x61\x74\x65\x4d\x65\x73\x73\x61\x67\x65\x00\x00\xaf\x00\x44\x69\x73\x70\x61\x74\x63\x68\x4d\x65\x73\x73\x61\x67\x65\x57\x00\x00\xef\x01\x4c\x6f\x61\x64\x49\x6d\x61\x67\x65\x57\x00\x00\x51\x01\x47\x65\x74\x4d\x65\x6e\x75\x49\x74\x65\x6d\x43\x6f\x75\x6e\x74\x00\x00\xa2\x02\x53\x65\x74\x4d\x65\x6e\x75\x49\x74\x65\x6d\x49\x6e\x66\x6f\x57\x00\x00\xb9\x01\x49\x6e\x73\x65\x72\x74\x4d\x65\x6e\x75\x49\x74\x65\x6d\x57\x00\x36\x02\x50\x6f\x73\x74\x4d\x65\x73\x73\x61\x67\x65\x57\x00\x00\x55\x53\x45\x52\x33\x32\x2e\x64\x6c\x6c\x00\x00\x2e\x01\x53\x68\x65\x6c\x6c\x5f\x4e\x6f\x74\x69\x66\x79\x49\x63\x6f\x6e\x57\x00\x53\x48\x45\x4c\x4c\x33\x32\x2e\x64\x6c\x6c\x00\xd7\x05\x70\x72\x69\x6e\x74\x66\x00\x00\x6b\x05\x63\x61\x6c\x6c\x6f\x63\x00\x00\x8b\x05\x66\x72\x65\x65\x00\x00\xc4\x05\x6d\x61\x6c\x6c\x6f\x63\x00\x00\x3c\x06\x77\x63\x73\x6e\x63\x70\x79\x5f\x73\x00\x4d\x53\x56\x43\x52\x31\x30\x30\x2e\x64\x6c\x6c\x00\x00\x34\x03\x5f\x6d\x61\x6c\x6c\x6f\x63\x5f\x63\x72\x74\x00\x19\x02\x5f\x65\x6e\x63\x6f\x64\x65\x64\x5f\x6e\x75\x6c\x6c\x00\xb0\x02\x5f\x69\x6e\x69\x74\x74\x65\x72\x6d\x00\xb1\x02\x5f\x69\x6e\x69\x74\x74\x65\x72\x6d\x5f\x65\x00\xc5\x01\x5f\x61\x6d\x73\x67\x5f\x65\x78\x69\x74\x00\x00\x31\x01\x5f\x5f\x43\x70\x70\x58\x63\x70\x74\x46\x69\x6c\x74\x65\x72\x00\xfb\x01\x5f\x63\x72\x74\x5f\x64\x65\x62\x75\x67\x67\x65\x72\x5f\x68\x6f\x6f\x6b\x00\x00\x53\x01\x5f\x5f\x63\x6c\x65\x61\x6e\x5f\x74\x79\x70\x65\x5f\x69\x6e\x66\x6f\x5f\x6e\x61\x6d\x65\x73\x5f\x69\x6e\x74\x65\x72\x6e\x61\x6c\x00\x00\x8d\x04\x5f\x75\x6e\x6c\x6f\x63\x6b\x00\x5b\x01\x5f\x5f\x64\x6c\x6c\x6f\x6e\x65\x78\x69\x74\x00\x23\x03\x5f\x6c\x6f\x63\x6b\x00\xc9\x03\x5f\x6f\x6e\x65\x78\x69\x74\x00\x21\x02\x5f\x65\x78\x63\x65\x70\x74\x5f\x68\x61\x6e\x64\x6c\x65\x72\x34\x5f\x63\x6f\x6d\x6d\x6f\x6e\x00\xea\x00\x45\x6e\x63\x6f\x64\x65\x50\x6f\x69\x6e\x74\x65\x72\x00\xca\x00\x44\x65\x63\x6f\x64\x65\x50\x6f\x69\x6e\x74\x65\x72\x00\xec\x02\x49\x6e\x74\x65\x72\x6c\x6f\x63\x6b\x65\x64\x45\x78\x63\x68\x61\x6e\x67\x65\x00\xb2\x04\x53\x6c\x65\x65\x70\x00\xe9\x02\x49\x6e\x74\x65\x72\x6c\x6f\x63\x6b\x65\x64\x43\x6f\x6d\x70\x61\x72\x65\x45\x78\x63\x68\x61\x6e\x67\x65\x00\x00\xc0\x04\x54\x65\x72\x6d\x69\x6e\x61\x74\x65\x50\x72\x6f\x63\x65\x73\x73\x00\x00\xc0\x01\x47\x65\x74\x43\x75\x72\x72\x65\x6e\x74\x50\x72\x6f\x63\x65\x73\x73\x00\xd3\x04\x55\x6e\x68\x61\x6e\x64\x6c\x65\x64\x45\x78\x63\x65\x70\x74\x69\x6f\x6e\x46\x69\x6c\x74\x65\x72\x00\x00\xa5\x04\x53\x65\x74\x55\x6e\x68\x61\x6e\x64\x6c\x65\x64\x45\x78\x63\x65\x70\x74\x69\x6f\x6e\x46\x69\x6c\x74\x65\x72\x00\x00\x03\x49\x73\x44\x65\x62\x75\x67\x67\x65\x72\x50\x72\x65\x73\x65\x6e\x74\x00\xa7\x03\x51\x75\x65\x72\x79\x50\x65\x72\x66\x6f\x72\x6d\x61\x6e\x63\x65\x43\x6f\x75\x6e\x74\x65\x72\x00\x93\x02\x47\x65\x74\x54\x69\x63\x6b\x43\x6f\x75\x6e\x74\x00\x00\xc5\x01\x47\x65\x74\x43\x75\x72\x72\x65\x6e\x74\x54\x68\x72\x65\x61\x64\x49\x64\x00\x00\xc1\x01\x47\x65\x74\x43\x75\x72\x72\x65\x6e\x74\x50\x72\x6f\x63\x65\x73\x73\x49\x64\x00\x79\x02\x47\x65\x74\x53\x79\x73\x74\x65\x6d\x54\x69\x6d\x65\x41\x73\x46\x69\x6c\x65\x54\x69\x6d\x65\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xba\x85\xdd\x54\x00\x00\x00\x00\x6a\x29\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x05\x00\x00\x00\x38\x29\x00\x00\x4c\x29\x00\x00\x60\x29\x00\x00\xe0\x14\x00\x00\xd0\x12\x00\x00\x60\x16\x00\x00\x10\x14\x00\x00\x90\x14\x00\x00\x76\x29\x00\x00\x8e\x29\x00\x00\x99\x29\x00\x00\x9e\x29\x00\x00\xa6\x29\x00\x00\x00\x00\x01\x00\x02\x00\x03\x00\x04\x00\x73\x79\x73\x74\x72\x61\x79\x2e\x64\x6c\x6c\x00\x61\x64\x64\x5f\x6f\x72\x5f\x75\x70\x64\x61\x74\x65\x5f\x6d\x65\x6e\x75\x5f\x69\x74\x65\x6d\x00\x6e\x61\x74\x69\x76\x65\x4c\x6f\x6f\x70\x00\x71\x75\x69\x74\x00\x73\x65\x74\x49\x63\x6f\x6e\x00\x73\x65\x74\x54\x6f\x6f\x6c\x74\x69\x70\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x4e\xe6\x40\xbb\xb1\x19\xbf\x44\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x01\x00\x18\x00\x00\x00\x18\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x01\x00\x02\x00\x00\x00\x30\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x01\x00\x09\x04\x00\x00\x48\x00\x00\x00\x58\x40\x00\x00\x5a\x01\x00\x00\xe4\x04\x00\x00\x00\x00\x00\x00\x3c\x61\x73\x73\x65\x6d\x62\x6c\x79\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x75\x72\x6e\x3a\x73\x63\x68\x65\x6d\x61\x73\x2d\x6d\x69\x63\x72\x6f\x73\x6f\x66\x74\x2d\x63\x6f\x6d\x3a\x61\x73\x6d\x2e\x76\x31\x22\x20\x6d\x61\x6e\x69\x66\x65\x73\x74\x56\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x30\x22\x3e\x0d\x0a\x20\x20\x3c\x74\x72\x75\x73\x74\x49\x6e\x66\x6f\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x75\x72\x6e\x3a\x73\x63\x68\x65\x6d\x61\x73\x2d\x6d\x69\x63\x72\x6f\x73\x6f\x66\x74\x2d\x63\x6f\x6d\x3a\x61\x73\x6d\x2e\x76\x33\x22\x3e\x0d\x0a\x20\x20\x20\x20\x3c\x73\x65\x63\x75\x72\x69\x74\x79\x3e\x0d\x0a\x20\x20\x20\x20\x20\x20\x3c\x72\x65\x71\x75\x65\x73\x74\x65\x64\x50\x72\x69\x76\x69\x6c\x65\x67\x65\x73\x3e\x0d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x72\x65\x71\x75\x65\x73\x74\x65\x64\x45\x78\x65\x63\x75\x74\x69\x6f\x6e\x4c\x65\x76\x65\x6c\x20\x6c\x65\x76\x65\x6c\x3d\x22\x61\x73\x49\x6e\x76\x6f\x6b\x65\x72\x22\x20\x75\x69\x41\x63\x63\x65\x73\x73\x3d\x22\x66\x61\x6c\x73\x65\x22\x3e\x3c\x2f\x72\x65\x71\x75\x65\x73\x74\x65\x64\x45\x78\x65\x63\x75\x74\x69\x6f\x6e\x4c\x65\x76\x65\x6c\x3e\x0d\x0a\x20\x20\x20\x20\x20\x20\x3c\x2f\x72\x65\x71\x75\x65\x73\x74\x65\x64\x50\x72\x69\x76\x69\x6c\x65\x67\x65\x73\x3e\x0d\x0a\x20\x20\x20\x20\x3c\x2f\x73\x65\x63\x75\x72\x69\x74\x79\x3e\x0d\x0a\x20\x20\x3c\x2f\x74\x72\x75\x73\x74\x49\x6e\x66\x6f\x3e\x0d\x0a\x3c\x2f\x61\x73\x73\x65\x6d\x62\x6c\x79\x3e\x50\x41\x50\x41\x44\x44\x49\x4e\x47\x58\x58\x50\x41\x44\x44\x49\x4e\x47\x50\x41\x44\x44\x49\x4e\x47\x58\x58\x50\x41\x44\x44\x49\x4e\x47\x50\x41\x44\x44\x49\x4e\x47\x58\x58\x50\x41\x44\x44\x49\x4e\x47\x50\x41\x44\x44\x49\x4e\x47\x58\x58\x50\x41\x44\x44\x49\x4e\x47\x50\x41\x44\x44\x49\x4e\x47\x58\x58\x50\x41\x44\x00\x10\x00\x00\xb4\x01\x00\x00\x22\x30\x30\x30\x47\x30\x51\x30\x69\x30\x71\x30\x76\x30\x7c\x30\x9f\x30\xa9\x30\xc1\x30\xc9\x30\xce\x30\xd4\x30\xe3\x30\xee\x30\xfe\x30\x18\x31\x35\x31\x3f\x31\x57\x31\x5f\x31\x64\x31\x6a\x31\xc1\x31\xec\x31\x16\x32\x26\x32\x2e\x32\x36\x32\x59\x32\x75\x32\x98\x32\xb7\x32\xc6\x32\xdd\x32\xe3\x32\x09\x33\x0e\x33\x16\x33\x25\x33\x2c\x33\x32\x33\x40\x33\x4a\x33\x65\x33\x73\x33\x78\x33\x80\x33\x8a\x33\x90\x33\x9a\x33\xa4\x33\xae\x33\xbb\x33\xd2\x33\xd9\x33\x29\x34\x35\x34\x4d\x34\x55\x34\x5a\x34\x60\x34\x6b\x34\x72\x34\x78\x34\x82\x34\xa8\x34\xae\x34\xb6\x34\xbe\x34\xc8\x34\xcf\x34\xfa\x34\x08\x35\x0e\x35\x7c\x35\x83\x35\x97\x35\xa2\x35\xc1\x35\xcb\x35\xe3\x35\xeb\x35\xf0\x35\x1b\x36\x2a\x36\x34\x36\x44\x36\x4e\x36\x61\x36\x6e\x36\x75\x36\x8c\x36\x96\x36\x9b\x36\xa0\x36\xb6\x36\xc2\x36\xe3\x36\xf1\x36\xfe\x36\x03\x37\x29\x37\x32\x37\x43\x37\x5b\x37\x70\x37\x75\x37\x7b\x37\x93\x37\x98\x37\xa4\x37\xb4\x37\xba\x37\xc1\x37\xd8\x37\xde\x37\xf2\x37\x0a\x38\x22\x38\x28\x38\x3b\x38\x5b\x38\x6c\x38\x77\x38\x7f\x38\xa7\x38\xae\x38\xb3\x38\xb8\x38\xbf\x38\xcc\x38\xdd\x38\xfa\x38\x07\x39\x1f\x39\x72\x39\x9f\x39\xe7\x39\x1f\x3a\x25\x3a\x2b\x3a\x31\x3a\x37\x3a\x3d\x3a\x44\x3a\x4b\x3a\x52\x3a\x59\x3a\x60\x3a\x67\x3a\x6e\x3a\x76\x3a\x7e\x3a\x86\x3a\x92\x3a\x9b\x3a\xa0\x3a\xa6\x3a\xb0\x3a\xb9\x3a\xc4\x3a\xd0\x3a\xd5\x3a\xe5\x3a\xea\x3a\xf0\x3a\xf6\x3a\x0c\x3b\x13\x3b\x1a\x3b\x28\x3b\x33\x3b\x39\x3b\x4c\x3b\x61\x3b\x6c\x3b\x82\x3b\x9a\x3b\xa4\x3b\xe1\x3b\xe6\x3b\x07\x3c\x0c\x3c\xc8\x3c\xcd\x3c\xdf\x3c\xfd\x3c\x11\x3d\x17\x3d\x7e\x3d\x84\x3d\x8a\x3d\x90\x3d\xa1\x3d\xbe\x3d\x0b\x3e\x10\x3e\x27\x3e\x4a\x3e\x57\x3e\x63\x3e\x6b\x3e\x73\x3e\x7f\x3e\xa8\x3e\xb0\x3e\xbc\x3e\xc2\x3e\xc8\x3e\xce\x3e\xd4\x3e\xda\x3e\x00\x20\x00\x00\x20\x00\x00\x00\x0c\x31\x40\x31\x44\x31\x34\x32\x38\x32\x00\x33\x08\x33\x0c\x33\x28\x33\x44\x33\x48\x33\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")