EMMA Coverage Report (generated Mon Mar 20 21:34:30 PST 2006)
[all classes][com.moesol.bindings.platform_sdk.windows_api]

COVERAGE SUMMARY FOR SOURCE FILE [PlatformSDK.java]

nameclass, %method, %block, %line, %
PlatformSDK.java100% (1/1)62%  (18/29)76%  (214/281)77%  (56.8/74)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class PlatformSDK100% (1/1)62%  (18/29)76%  (214/281)77%  (56.8/74)
FormatMessage (int): String 0%   (0/1)0%   (0/3)0%   (0/1)
GetAsyncKeyState (int): short 0%   (0/1)0%   (0/3)0%   (0/1)
GetDeviceCaps (HDC, int): int 0%   (0/1)0%   (0/5)0%   (0/1)
GetSystemMetrics (int): int 0%   (0/1)0%   (0/3)0%   (0/1)
PlatformSDK (): void 0%   (0/1)0%   (0/3)0%   (0/1)
PostMessage (HWND, int, int, Object): void 0%   (0/1)0%   (0/10)0%   (0/3)
PostMessage (HWND, int, int, int): void 0%   (0/1)0%   (0/10)0%   (0/3)
RegEnumKey (HKEY, int, String []): int 0%   (0/1)0%   (0/6)0%   (0/1)
RegSetKeyEx (HKEY, String, Object): void 0%   (0/1)0%   (0/5)0%   (0/2)
SendMessage (HWND, int, int, Object): int 0%   (0/1)0%   (0/7)0%   (0/1)
SendMessage (HWND, int, int, int): int 0%   (0/1)0%   (0/7)0%   (0/1)
RegNotifyChangeKeyValue (HKEY, boolean, int, HANDLE, boolean): void 100% (1/1)81%  (13/16)94%  (2.8/3)
GetMessage (MSG, HWND, int, int): boolean 100% (1/1)89%  (17/19)83%  (5/6)
<static initializer> 100% (1/1)100% (36/36)100% (7/7)
DispatchMessage (MSG): int 100% (1/1)100% (4/4)100% (1/1)
GetCurrentDirectory (String []): int 100% (1/1)100% (3/3)100% (1/1)
GetDoubleClickTime (): long 100% (1/1)100% (2/2)100% (1/1)
GetLastError (): int 100% (1/1)100% (2/2)100% (1/1)
GetTextExtentPoint32 (HDC, String, SIZE []): void 100% (1/1)100% (18/18)100% (5/5)
RegCloseKey (HKEY): void 100% (1/1)100% (9/9)100% (4/4)
RegCreateKeyEx (HKEY, String, int, String, int, int, SECURITY_ATTRIBUTES, HKE... 100% (1/1)100% (30/30)100% (5/5)
RegDeleteKey (HKEY, String): void 100% (1/1)100% (8/8)100% (3/3)
RegDeleteValue (HKEY, String): void 100% (1/1)100% (8/8)100% (3/3)
RegOpenKeyEx (HKEY, String, int, int, HKEY []): void 100% (1/1)100% (27/27)100% (5/5)
RegQueryValue (HKEY, String, Object []): void 100% (1/1)100% (9/9)100% (3/3)
RegSetValueEx (HKEY, String, Object): void 100% (1/1)100% (9/9)100% (3/3)
SetCurrentDirectory (String): boolean 100% (1/1)100% (3/3)100% (1/1)
throwWin32OnBad_LRESULT (int): void 100% (1/1)100% (8/8)100% (3/3)
throwWin32OnFalse (boolean): void 100% (1/1)100% (8/8)100% (3/3)

1/*
2 * $Id: PlatformSDK.java,v 1.12 2006/03/04 06:04:54 hastings Exp $
3 *
4 * (c) Copyright, Moebius Solutions, Inc., 2004
5 *
6 *                       All Rights Reserved
7 *
8 * This material may be reproduced by or for the U. S. Government
9 * pursuant to the copyright license under the clause at
10 * DFARS 252.227-7014 (OCT 2001).
11 */
12 
13package com.moesol.bindings.platform_sdk.windows_api;
14 
15/**
16 * @author Robert Hastings
17 */
18public class PlatformSDK {
19        public static final int ERROR_SUCCESS = 0;
20        public static final int ERROR_INVALID_FUNCTION = 1;
21        public static final int ERROR_FILE_NOT_FOUND = 2;
22        public static final int ERROR_NO_MORE_ITEMS = 259;
23        public static final int RPC_E_WRONG_THREAD = 0x8001010E;
24        
25        // Root Keys
26        public static final HKEY HKEY_CLASSES_ROOT = new HKEY(0x80000000);
27        public static final HKEY HKEY_CURRENT_USER = new HKEY(0x80000001);
28        public static final HKEY HKEY_LOCAL_MACHINE = new HKEY(0x80000002);
29        public static final HKEY HKEY_USERS  = new HKEY(0x80000003);
30        public static final HKEY HKEY_PERFORMANCE_DATA = new HKEY(0x80000004);
31        // #if(WINVER >= 0x0400)
32        public static final HKEY HKEY_CURRENT_CONFIG = new HKEY(0x80000005);
33        public static final HKEY HKEY_DYN_DATA = new HKEY(0x80000006);
34        
35        /* Device Parameters for GetDeviceCaps() */
36        public static final int DRIVERVERSION =  0;
37        public static final int TECHNOLOGY =     2;
38        public static final int HORZSIZE =       4;
39        public static final int VERTSIZE =       6;
40        public static final int HORZRES =        8;
41        public static final int VERTRES =        10;
42        public static final int BITSPIXEL =      12;
43        public static final int PLANES =         14;
44        public static final int NUMBRUSHES =     16;
45        public static final int NUMPENS =        18;
46        public static final int NUMMARKERS =     20;
47        public static final int NUMFONTS =       22;
48        public static final int NUMCOLORS =      24;
49        public static final int PDEVICESIZE =    26;
50        public static final int CURVECAPS =      28;
51        public static final int LINECAPS =       30;
52        public static final int POLYGONALCAPS =  32;
53        public static final int TEXTCAPS =       34;
54        public static final int CLIPCAPS =       36;
55        public static final int RASTERCAPS =     38;
56        public static final int ASPECTX =        40;
57        public static final int ASPECTY =        42;
58        public static final int ASPECTXY =       44;
59 
60        // #if(WINVER >= 0x0500)
61        public static final int SHADEBLENDCAPS =  45;
62        // #endif /* WINVER >= 0x0500 */
63 
64        public static final int LOGPIXELSX =     88;
65        public static final int LOGPIXELSY =     90;
66 
67        public static final int SIZEPALETTE =   104;
68        public static final int NUMRESERVED =   106;
69        public static final int COLORRES =      108;
70 
71        // Key Access        
72        public static final int STANDARD_RIGHTS_ALL = 0x001F0000;
73        public static final int READ_CONTROL = 0x00020000;
74        public static final int SYNCHRONIZE = 0x00100000;
75        public static final int STANDARD_RIGHTS_READ = READ_CONTROL;
76        public static final int STANDARD_RIGHTS_WRITE = READ_CONTROL;
77        public static final int STANDARD_RIGHTS_EXECUTE = READ_CONTROL;
78        public static final int KEY_QUERY_VALUE = 0x0001;
79        public static final int KEY_SET_VALUE = 0x0002;
80        public static final int KEY_CREATE_SUB_KEY = 0x0004;
81        public static final int KEY_ENUMERATE_SUB_KEYS = 0x0008;
82        public static final int KEY_NOTIFY = 0x0010;
83        public static final int KEY_CREATE_LINK = 0x0020;
84        public static final int KEY_READ =
85                ((STANDARD_RIGHTS_READ
86                        | KEY_QUERY_VALUE
87                        | KEY_ENUMERATE_SUB_KEYS
88                        | KEY_NOTIFY)
89                        & (~SYNCHRONIZE));
90        public static final int KEY_WRITE =
91                ((STANDARD_RIGHTS_WRITE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY)
92                        & (~SYNCHRONIZE));
93        public static final int KEY_EXECUTE = ((KEY_READ) & (~SYNCHRONIZE));
94        public static final int KEY_ALL_ACCESS =
95                ((STANDARD_RIGHTS_ALL
96                        | KEY_QUERY_VALUE
97                        | KEY_SET_VALUE
98                        | KEY_CREATE_SUB_KEY
99                        | KEY_ENUMERATE_SUB_KEYS
100                        | KEY_NOTIFY
101                        | KEY_CREATE_LINK)
102                        & (~SYNCHRONIZE));
103 
104        // Special Options
105        public static final int REG_OPTION_RESERVED = 0x00000000;           // Parameter is reserved
106        public static final int REG_OPTION_NON_VOLATILE = 0x00000000;   // Key is preserved
107                                                                                                                                        // when system is rebooted
108        public static final int REG_OPTION_VOLATILE = 0x00000001;                  // Key is not preserved
109                                                                                                                                        // when system is rebooted
110        // Result values
111        public static final int REG_CREATED_NEW_KEY = 0x00000001;
112        public static final int REG_OPENED_EXISTING_KEY = 0x00000002;
113 
114        public static final int REG_NOTIFY_CHANGE_NAME = 0x1;
115        public static final int REG_NOTIFY_CHANGE_ATTRIBUTES = 0x2;
116        public static final int REG_NOTIFY_CHANGE_LAST_SET = 0x4;
117        public static final int REG_NOTIFY_CHANGE_SECURITY = 0x8;
118        
119        // System metrics
120        public static final int SM_CXSCREEN = 0;
121        public static final int SM_CYSCREEN = 1;
122        public static final int SM_CXVSCROLL = 2;
123        public static final int SM_CYHSCROLL = 3;
124        public static final int SM_CYCAPTION = 4;
125        public static final int SM_CXBORDER = 5;
126        public static final int SM_CYBORDER = 6;
127        public static final int SM_CXDLGFRAME = 7;
128        public static final int SM_CYDLGFRAME = 8;
129        public static final int SM_CYVTHUMB = 9;
130        public static final int SM_CXHTHUMB = 10;
131        public static final int SM_CXICON = 11;
132        public static final int SM_CYICON = 12;
133        public static final int SM_CXCURSOR = 13;
134        public static final int SM_CYCURSOR = 14;
135        public static final int SM_CYMENU = 15;
136        public static final int SM_CXFULLSCREEN = 16;
137        public static final int SM_CYFULLSCREEN = 17;
138        public static final int SM_CYKANJIWINDOW = 18;
139        public static final int SM_MOUSEPRESENT = 19;
140        public static final int SM_CYVSCROLL = 20;
141        public static final int SM_CXHSCROLL = 21;
142        public static final int SM_DEBUG = 22;
143        public static final int SM_SWAPBUTTON = 23;
144        public static final int SM_RESERVED1 = 24;
145        public static final int SM_RESERVED2 = 25;
146        public static final int SM_RESERVED3 = 26;
147        public static final int SM_RESERVED4 = 27;
148        public static final int SM_CXMIN = 28;
149        public static final int SM_CYMIN = 29;
150        public static final int SM_CXSIZE = 30;
151        public static final int SM_CYSIZE = 31;
152        public static final int SM_CXFRAME = 32;
153        public static final int SM_CYFRAME = 33;
154        public static final int SM_CXMINTRACK = 34;
155        public static final int SM_CYMINTRACK = 35;
156        public static final int SM_CXDOUBLECLK = 36;
157        public static final int SM_CYDOUBLECLK = 37;
158        public static final int SM_CXICONSPACING = 38;
159        public static final int SM_CYICONSPACING = 39;
160        public static final int SM_MENUDROPALIGNMENT = 40;
161        public static final int SM_PENWINDOWS = 41;
162        public static final int SM_DBCSENABLED = 42;
163        public static final int SM_CMOUSEBUTTONS = 43;
164        
165        // Virtual keys
166        public static final int VK_LBUTTON = 0x01;
167        public static final int VK_RBUTTON = 0x02;
168        public static final int VK_CANCEL = 0x03;
169        public static final int VK_MBUTTON = 0x04;
170        
171        public static final int VK_SHIFT = 0x10;
172        public static final int VK_CONTROL = 0x11;
173        public static final int VK_MENU = 0x12;
174        public static final int VK_CAPITAL = 0x14;
175        
176        // ShowWindow constants
177        public static final int SW_HIDE             = 0;
178        public static final int SW_SHOWNORMAL       = 1;
179        public static final int SW_NORMAL           = 1;
180        public static final int SW_SHOWMINIMIZED    = 2;
181        public static final int SW_SHOWMAXIMIZED    = 3;
182        public static final int SW_MAXIMIZE         = 3;
183        public static final int SW_SHOWNOACTIVATE   = 4;
184        public static final int SW_SHOW             = 5;
185        public static final int SW_MINIMIZE         = 6;
186        public static final int SW_SHOWMINNOACTIVE  = 7;
187        public static final int SW_SHOWNA           = 8;
188        public static final int SW_RESTORE          = 9;
189        public static final int SW_SHOWDEFAULT      = 10;
190        public static final int SW_FORCEMINIMIZE    = 11;
191        public static final int SW_MAX              = 11;
192        
193        // IPropertyPageSite constants
194    public static final int        PROPPAGESTATUS_DIRTY        = 0x1;
195    public static final int        PROPPAGESTATUS_VALIDATE        = 0x2;
196    public static final int        PROPPAGESTATUS_CLEAN        = 0x4;
197        
198        /**
199         * See PlatformSDK: GetMessage
200         * @param lpMsg
201         * @param hWnd
202         * @param wMsgFilterMin
203         * @param wMsgFilterMax
204         * @return false if WM_QUIT was posted
205         * @throws Win32Exception
206         */
207        public static boolean GetMessage(MSG lpMsg, HWND hWnd, int wMsgFilterMin,
208                        int wMsgFilterMax) {
209                int r = jni_GetMessage(lpMsg._getStructureBytes(),
210                                HWND._safeGetHandle(hWnd), wMsgFilterMin, wMsgFilterMax);
211                if (r == -1) {
212                        throwWin32OnFalse(false);
213                }
214                if (r == 0) {
215                        return false;
216                }
217                return true;
218        }
219        /**
220         * See PlatformSDK: DispatchMessage
221         * @param msg
222         * @return LRESULT
223         */
224        public static int DispatchMessage(MSG msg) {
225                return jni_DispatchMessage(msg._getStructureBytes());
226        }
227 
228        /**
229     * See PlatformSDK: PostMessage
230     * @param hWnd
231     * @param Msg
232     * @param wParam
233     * @param lParam
234         * @throws Win32Exception
235     */
236    public static void PostMessage(
237        HWND hWnd,
238        int Msg,
239        int wParam,
240        int lParam) {
241        boolean success = jni_PostMessage(HWND._safeGetHandle(hWnd), Msg, wParam, lParam);
242        throwWin32OnFalse(success);
243    }
244    /**
245     * Post a message to a window that references a java object. Since
246     * the lifetime of the message is longer than the JNI call this method
247     * will call NewGlobalRef for the object parameter. The window receiving
248     * this message should call DeleteGlobalRef for the lParam.
249     * 
250     * @param hWnd
251     * @param Msg
252     * @param wParam
253     * @param lParam
254     */
255    public static void PostMessage(HWND hWnd, int Msg, int wParam, Object lParam) {
256        boolean r = jni_PostMessage(HWND._safeGetHandle(hWnd), Msg, wParam, lParam);
257        throwWin32OnFalse(r);
258    }
259    
260    /**
261     * Format a system error code into a message.
262     * The full functionality is not exposed by this method, only the conversion
263     * from error code to system error text is currently supported.
264     * 
265     * @param lresult
266     * @return the String of the formated message.
267     */
268    public static String FormatMessage(int lresult) {
269        return jni_FormatMessage(lresult);
270    }
271    /**
272     * See PlatformSDK GetAsyncKeyState
273     * @param vKey
274     * @return
275     */
276        public static short GetAsyncKeyState(
277          int vKey   // virtual-key code
278        ) {
279                return jni_GetAsyncKeyState(vKey);
280        }
281        private static native short jni_GetAsyncKeyState(int vKey);
282        
283    public static int GetDeviceCaps(HDC hdc, int nIndex) {
284            return jni_GetDeviceCaps(hdc._getHandle(), nIndex);
285    }
286    public static int GetLastError() {
287        return jni_GetLastError();
288    }
289    public static void GetTextExtentPoint32(
290        HDC hdc,
291        String lpString,
292        SIZE[] out_size) 
293    {
294            SIZE size = new SIZE();
295        boolean r =
296            jni_GetTextExtentPoint32(
297                hdc._getHandle(),
298                lpString,
299                size._getStructureBytes());
300        throwWin32OnFalse(r);
301                out_size[0] = size;
302        }
303    public static int GetSystemMetrics(int nIndex) {
304            return jni_GetSystemMetrics(nIndex);
305        }
306    private static native int jni_GetSystemMetrics(int nIndex);
307    
308    public static void RegOpenKeyEx(
309        HKEY hKey,
310        String subKeyName,
311        int options, // reserved must be null
312        int samDesired,
313        HKEY[] outKey) 
314    {
315            long[] out_key = { 0 };
316        int lresult = jni_RegOpenKeyEx(hKey._getHandle(), subKeyName, options, samDesired, out_key);
317        throwWin32OnBad_LRESULT(lresult);
318        outKey[0] = new HKEY(out_key[0]);
319    }
320    
321    public static int RegEnumKey(HKEY hKey, int index, String[] out_name) {
322            return jni_RegEnumKey(hKey._getHandle(), index, out_name);
323    }
324    public static void RegQueryValue(
325        HKEY openedKey,
326        String subKeyName,
327        Object[] outObject) 
328    {
329        int lresult =
330            jni_RegQueryValueEx(openedKey._getHandle(), subKeyName, outObject);
331        throwWin32OnBad_LRESULT(lresult);
332    }
333    public static void RegCloseKey(HKEY aKey) {
334        int lresult = jni_RegCloseKey(aKey._getHandle());
335        throwWin32OnBad_LRESULT(lresult);
336        aKey.detach();
337    }
338    /**
339     * @deprecated As of jSegue 1.5 replaced by {@link #RegSetValueEx(HKEY, String, Object)}
340     * 
341     * @param openedKey
342     * @param subKeyName
343     * @param valueToSet
344     */
345    public static void RegSetKeyEx(
346            HKEY openedKey,
347            String subKeyName,
348            Object valueToSet) 
349    {
350            RegSetValueEx(openedKey, subKeyName, valueToSet);
351    }
352    
353    public static void RegSetValueEx(
354        HKEY openedKey,
355        String subKeyName,
356        Object valueToSet) 
357    {
358        int lresult = 
359            jni_RegSetValueEx(openedKey._getHandle(), subKeyName, valueToSet);
360        throwWin32OnBad_LRESULT(lresult);
361    }
362    
363    public static boolean SetCurrentDirectory(String dir) {
364            return jni_SetCurrentDirectory(dir);
365    }
366    
367    public static native boolean jni_SetCurrentDirectory(String dir) ;
368 
369    public static int GetCurrentDirectory(String [] out_dir) {
370            return jni_GetCurrentDirectory(out_dir);
371    }
372    
373    public static native int jni_GetCurrentDirectory(String [] out_dir);
374    
375    /**
376     * Currently this method doesn't supprot the LPSECURITY_ATTRIBUTES
377     * parameter of the actual win32 call.
378     */ 
379    public static void RegCreateKeyEx(
380        HKEY hKey,
381        String lpSubKey,                          // subkey name
382        int Reserved,                             // reserved
383        String lpClass,                           // class string
384        int dwOptions,                            // special options
385        int samDesired,                           // desired security access
386        SECURITY_ATTRIBUTES secAttrs,  // ** NULL in java for now **
387        HKEY [] phkResult,                           // key handle 
388        long [] lpdwDisposition                   // disposition value buffer
389        )
390    {
391            long[] out_key = { 0 };
392        int lresult =
393            jni_RegCreateKeyEx(
394                hKey._getHandle(),
395                lpSubKey,
396                Reserved,
397                lpClass,
398                dwOptions,
399                samDesired,
400                // NULL on the SEC_ATTRS
401                out_key,
402                lpdwDisposition
403                );
404        throwWin32OnBad_LRESULT(lresult);
405        phkResult[0] = new HKEY(out_key[0]); 
406    }
407    public static void RegDeleteKey(HKEY hKey, String subKey){
408        int lresult = jni_RegDeleteKey(hKey._getHandle(), subKey);
409        throwWin32OnBad_LRESULT(lresult);
410    }
411    public static void RegDeleteValue(HKEY hKey, String valueName) {
412            int lresult = jni_RegDeleteValue(hKey._getHandle(), valueName);
413            throwWin32OnBad_LRESULT(lresult);
414    }
415    public static void RegNotifyChangeKeyValue(
416        HKEY hKey,
417        boolean bWatchSubtree,
418        int dwNotifyFilter,
419        HANDLE event,
420        boolean fAsynchronous) 
421    {
422        int lresult;
423        lresult =
424            jni_RegNotifyChangeKeyValue(
425                hKey._getHandle(),
426                bWatchSubtree,
427                dwNotifyFilter,
428                event != null ? event._getHandle() : 0,
429                fAsynchronous);
430        throwWin32OnBad_LRESULT(lresult);
431    }
432        /**
433         * See PlatformSDK: SendMessage
434         */
435    public static int SendMessage(HWND hWnd, int Msg, int wParam, int lParam) {
436        return jni_SendMessage(hWnd._getHandle(), Msg, wParam, lParam);
437    }
438        /**
439         * See PlatformSDK: SendMessage
440         */
441    public static int SendMessage(
442        HWND hWnd,
443        int Msg,
444        int wParam,
445        Object lParam) {
446        return jni_SendMessage(hWnd._getHandle(), Msg, wParam, lParam);
447    }
448    /**
449     * See PlatformSDK: GetDoubleClickTime
450     */
451    public static long GetDoubleClickTime() {
452            return jni_GetDoubleClickTime();
453    }
454 
455    static void throwWin32OnFalse(boolean success) {
456                if (!success) {
457                        throw new Win32Exception(GetLastError());
458                }
459    }
460    static void throwWin32OnBad_LRESULT(int lresult) {
461                if (lresult != ERROR_SUCCESS) {
462                        throw new Win32Exception(lresult);
463                }
464    }
465    
466        private static native int jni_GetMessage(byte[] msg, long hWnd,
467                        int msgFilterMin, int msgFilterMax);
468        private static native int jni_DispatchMessage(byte[] bs);
469    private static native boolean jni_PostMessage(
470        long hWnd,
471        int Msg,
472        int wParam,
473        int lParam);
474    private static native boolean jni_PostMessage(
475        long hWnd,
476        int Msg,
477        int wParam,
478        Object lParam);
479    private static native String jni_FormatMessage(int lresult);
480    private static native int jni_GetLastError();
481    private static native int jni_GetDeviceCaps(long hdc, int index);
482    private static native boolean jni_GetTextExtentPoint32(
483        long hdc,
484        String s,
485        byte[] size);
486    private static native int jni_RegOpenKeyEx(
487        long keyToOpen, 
488        String subKeyName, 
489        int options, // must be zero
490        int samDesired,
491        long[] out_key);
492    private static native int jni_RegEnumKey(
493            long hKey,
494                int index,
495                String[] out_name
496    );
497    private static native int jni_RegQueryValueEx(
498        long openedKey,
499        String subKeyName,
500        Object [] out);
501    private static native int jni_RegSetValueEx(
502        long openedKey,
503        String subKeyName,
504        Object valueToSet);
505    private static native int jni_RegCloseKey(long aKey);
506    private static native int jni_RegCreateKeyEx(
507        long hKey,                                // handle to open key
508        String lpSubKey,                          // subkey name
509        int Reserved,                             // reserved
510        String lpClass,                           // class string
511        int dwOptions,                            // special options
512        int samDesired,                           // desired security access
513        // NULL in java for now LPSECURITY_ATTRIBUTES lpSecurityAttributes, // inheritance
514        long[] out_key,                           // key handle 
515        long [] lpdwDisposition                   // disposition value buffer
516        );
517    private static native int jni_RegDeleteKey(long hKey, String subKey);
518    private static native int jni_RegDeleteValue(long hKey, String valueName);
519    private static native int jni_RegNotifyChangeKeyValue(
520        long hKey,
521        boolean bWatchSubtree,
522        int dwNotifyFilter,
523        long hEvent,
524        boolean fAsynchronous);
525        private static native int jni_SendMessage(
526                long hWnd,
527                int Msg,
528                int wParam,
529                int lParam);
530        private static native int jni_SendMessage(
531                long hWnd,
532                int Msg,
533                int wParam,
534                Object lParam);
535        private static native long jni_GetDoubleClickTime();
536}

[all classes][com.moesol.bindings.platform_sdk.windows_api]
EMMA 2.0.5312 (C) Vladimir Roubtsov