; uncaps.asm
; beta 01: BIOS エリアの書き込みではうまくいかない.
; beta 02: keybord にコマンド送信
; beta 03: debug 用 VRAM 出力つきで安定したようだ。
; 2011.03.13 beta03
;参考文献
;http://w...content-available-to-author-only...o.jp/dp/4756101305/
;http://w...content-available-to-author-only...o.jp/dp/4756101062/
;
;for MASM6
;assembling
;----------------------------------------------------
;ASFLAGS = -nologo -Cx -c
;LD = link
;LDFLAGS = /NOL /NOI
;PROGRAM = uncaps.com
;OBJS = uncaps.obj
;.asm.obj:
; @$(AS) $(ASFLAGS) $< > error.txt
;$(PROGRAM) : $(OBJS)
; @$(LD) /t $(LDFLAGS) $(OBJS), $(PROGRAM);
;----------------------------------------------------
VRAMOFFSET2 equ 2 * (80 * 24 + 78)
DebugVRAMOut MACRO v
push ax
push ds
push bx
mov bh, 0
mov ax, 0A000h
mov ds, ax
mov word ptr ds:[VRAMOFFSET2], v
pop bx
pop ds
pop ax
endm
;----------------------------------------------------
dosseg
.model tiny
LF equ 0ah
CR equ 0dh
TAB equ 09h
SPACE equ 20h
.code
org 002ch
envseg label word
org 0081h
cmdtail label byte
org 0100h
;---------------------------------------------------------
; regident-al part
entry: jmp main
ID db 'UNCAPS'
ID_len equ $ - ID
old09 label dword
old09_off dw ?
old09_seg dw ?
old2f label dword
old2f_off dw ?
old2f_seg dw ?
in09flag db 0
func_no db ? ; 使用するファンクション番号
;------------------------------------------------------
; int 09h handler
KbReceiveData proc near
mov cx,8000H
RdyCheckLoop:
in al,0043H
test al,02H
jnz Ready
loop RdyCheckLoop
stc
ret
Ready:
mov dx,005FH
mov cx,18H
ReceiveLoop:
out dx,al
loop ReceiveLoop
;
in al,0043H
and al,38H
jnz ReceiveError
mov al,00010110B
out 0043H,al
mov cx,0007H
@@WaitLoop3: out dx,al
loop @@WaitLoop3
in al,0041H
clc
ret
ReceiveError:
mov al,00010100B
out 0043H,al
mov cx,0007H
@@WaitLoop4: out dx,al
loop @@WaitLoop4
in al,0041H
stc
ret
KbReceiveData endp
KBSendCommand proc near
;input register-ah
SendRetry:
mov al,00010111B
out 0043H,al
mov dx, 005FH
mov cx, 0007H
@@WaitLoop1:
out dx, al
loop @@WaitLoop1
mov al, ah
out 0041H, al
mov cx, 0007H
@@WaitLoop2:
out dx, al
loop @@WaitLoop2
;
mov al, 00010110B
out 0043H, al
;
mov bl, 00H
AckRetry:
call KbReceiveData
jc TimeOut
cmp al, 0faH
jne NotAck
clc
ret
NotAck:
cmp al,0FCH
je SendRetry
inc bl
cmp bl, 04H
jne AckRetry
TimeOut:
stc
ret
KBSendCommand endp
CAPSWORK equ 053ah
Send8251CapsOff proc near
;inhibit kb interrupt
;DebugVRAMOut 'D'
or al, 02h
out 0002h, al
;send 9d for LED
;DebugVRAMOut 'E'
mov ah, 9dh
call KBSendCommand
jc @@send_end
;
;DebugVRAMOut 'F'
mov ax, 0000h
mov ds, ax
mov ah, ds:[CAPSWORK]
shl ah, 1
and ah, 08h
or ah, 70h
call KBSendCommand
@@send_end:
;DebugVRAMOut 'G'
mov ah, 03H
int 18H
;DebugVRAMOut 'H'
cli
in al, 0002H
and al, NOT 02H
out 0002H,al
sti
;DebugVRAMOut 'I'
;wait 50ms
mov dx, 005fh
mov cx, 1000h
@@waitloop:
out dx, al
loop @@Waitloop
;DebugVRAMOut 'J'
ret
Send8251CapsOff endp
CAPSMASK equ 02h
VRAMOFFSET equ 2 * (80 * 24 + 79)
myint09 proc far
cmp cs:in09flag, 0
jne @@nop09
inc cs:in09flag
pushf
call cs:[old09]
push ax
push ds
push dx
push cx
push bx
DebugVRAMOut 'A'
mov ax, 0000h
mov ds, ax
mov al, ds:[CAPSWORK]
and al, CAPSMASK
mov ax, 0A000h
mov ds, ax
jnz @@capson
@@capsoff:
jp @@capsnext
@@capson:
DebugVRAMOut 'B'
call Send8251CapsOff
DebugVRAMOut 'C'
@@capsnext:
;insted call KB BIOS-reset int 18h-03h in Send8251CapsOff
; mov ax, 0000h
; mov ds, ax
; mov al, ds:[CAPSWORK]
; and al, not CAPSMASK
; mov ds:[CAPSWORK], al
pop bx
pop cx
pop dx
pop ds
pop ax
dec cs:in09flag
@@nop09:
iret
myint09 endp
;-------------------------------------------------------------
myint2F proc far
cmp ah, cs:func_no
jne @@chain
cmp al, 00h
je @@f00
cmp al, 01h
je @@f01
jmp @@exit2F
@@f00:
mov ax, cs ;return al=0ffh, es:di=IDstring
mov es, ax
mov di, offset ID
mov al, 0ffh
jmp @@exit2F ;ax != 0000h
@@f01:
mov dx, cs
mov ax, 3509h
int 21h
mov ax, es
sub ax, dx
jnz @@exit2F ;ax != 0000h
mov ax, 352fh
int 21h
mov ax, es
sub ax, dx
jnz @@exit2F ;ax != 0000h
mov es, dx; ;ax == 0000h
@@exit2F:
iret
@@chain:
jmp cs:[old2F]
myint2F endp
TSRSIZE equ $ - entry + 256
;======================================================================
;initialize
.data
msg_stay db 'uncap が常駐しました.', CR, LF, '$'
msg_release db 'uncap を解放しました.', CR, LF, '$'
msg_notexist db 'uncap は常駐していません.', CR, LF, '$'
msg_already db 'uncap はすでに常駐しています.', CR, LF, '$'
msg_hooked db 'uncap: INT 09h/2Fh のいずれかがフックされ'
db '解放できません.', CR, LF, '$'
msg_funcfull db 'uncap: INT 2Fh に未使用ファンクションがありません.'
db CR, LF, '$'
.code
main proc near
mov si, offset cmdtail
cld
@@getarg:
lodsb
cmp al, SPACE
je @@getarg
cmp al, TAB
je @@getarg
mov ah, al ; ah = 引数の最初の文字
lodsb ; al = 引数の次の文字
cmp ax, '-r'
je @@release
@@stay:
call TSRcheck
jc @@skip1
jmp @@already
@@skip1:
call getfunc
jnc @@skip2
jmp @@funcfull
@@skip2:
mov func_no, ah
mov ax, 3509h
int 21h
mov old09_off, bx
mov old09_seg, es
mov ax, 352fh
int 21h
mov old2F_off, bx
mov old2F_seg, es
mov dx, offset myint09
mov ax, 2509h
int 21h
mov dx, offset myint2f
mov ax, 252fh
int 21h
mov es, envseg
mov ah, 49h
int 21h
mov dx, offset msg_stay
mov ah, 09h
int 21h
mov dx, (TSRSIZE + 15) / 16
mov ax, 3100h
int 21h
@@release:
call TSRcheck
jc @@notexist
mov ah, func_no
mov al, 01h
int 2fh
or ax, ax
jnz @@hooked
push ds
lds dx, es:[old09] ; ds:dx <= old vec
mov ax, 2509h
int 21h
lds dx, es:[old2f] ; ds:dx <= old vec
mov ax, 252fh
int 21h
pop ds
mov ah, 49h
int 21h
mov dx, offset msg_release
mov ah, 09h
int 21h
mov ax, 4c00h
int 21h
@@already:
mov dx, offset msg_already
jmp @@error
@@funcfull:
mov dx, offset msg_funcfull
jmp @@error
@@notexist:
mov dx, offset msg_notexist
jmp @@error
@@hooked:
mov dx, offset msg_hooked
@@error:
mov ah, 09h
int 21h
mov ax, 4c01h
int 21h
main endp
;--------------------------------------------------------
TSRcheck proc near
mov ah, 0c0h
@@tc_loop:
push ax
mov al, 00h
int 2fh
cmp al, 0ffh
pop ax
jne @@tc_nextfunc
;if residented
;es:di="uncaps"
mov si, offset ID
mov cx, ID_len
cld
repz cmpsb
jz @@tc_found
@@tc_nextfunc:
inc ah
jnz @@tc_loop
@@tc_notfound:
stc
ret
@@tc_found:
mov func_no, ah
clc
ret
TSRcheck endp
;-----------------------------------------------------
getfunc proc near
mov ah, 0c0h
@@fc_loop:
push ax
mov al, 00h
int 2fh
cmp al, 00h
pop ax
je @@fc_found
inc ah
jnz @@fc_loop
@@fc_notfound:
stc
ret
@@fc_found:
clc
ret
getfunc endp
end entry
;
;
; 2011.03.13 beta03
OyB1bmNhcHMuYXNtCjsgYmV0YSAwMTogQklPUyDjgqjjg6rjgqLjga7mm7jjgY3ovrzjgb/jgafjga/jgYbjgb7jgY/jgYTjgYvjgarjgYQuCjsgYmV0YSAwMjoga2V5Ym9yZCDjgavjgrPjg57jg7Pjg4npgIHkv6EKOyBiZXRhIDAzOiBkZWJ1ZyDnlKggVlJBTSDlh7rlipvjgaTjgY3jgaflronlrprjgZfjgZ/jgojjgYbjgaDjgIIKCjsgMjAxMS4wMy4xMyBiZXRhMDMKCjvlj4LogIPmlofnjK4KO2h0dHA6Ly93Li4uY29udGVudC1hdmFpbGFibGUtdG8tYXV0aG9yLW9ubHkuLi5vLmpwL2RwLzQ3NTYxMDEzMDUvCjtodHRwOi8vdy4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4uby5qcC9kcC80NzU2MTAxMDYyLwo7CgoKCjtmb3IgTUFTTTYKO2Fzc2VtYmxpbmcKOy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KO0FTRkxBR1MgPSAtbm9sb2dvIC1DeCAtYwo7TEQgPSBsaW5rCjtMREZMQUdTID0gL05PTCAvTk9JCjtQUk9HUkFNID0gdW5jYXBzLmNvbQo7T0JKUyA9IHVuY2Fwcy5vYmoKOy5hc20ub2JqOgo7CUAkKEFTKSAkKEFTRkxBR1MpICQ8ID4gZXJyb3IudHh0CjskKFBST0dSQU0pIDogJChPQkpTKQo7CUAkKExEKSAvdCAkKExERkxBR1MpICQoT0JKUyksICQoUFJPR1JBTSk7CjstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpWUkFNT0ZGU0VUMiAgICAgICAgIGVxdSAgICAgMiAqICg4MCAqIDI0ICsgNzgpCkRlYnVnVlJBTU91dCAgICAgICAgTUFDUk8gICB2CiAgICAgICAgICAgICAgICAgICAgcHVzaCAgICBheAogICAgICAgICAgICAgICAgICAgIHB1c2ggICAgZHMKICAgICAgICAgICAgICAgICAgICBwdXNoICAgIGJ4CgogICAgICAgICAgICAgICAgICAgIG1vdiAgICAgYmgsIDAKICAgICAgICAgICAgICAgICAgICBtb3YgICAgIGF4LCAwQTAwMGgKICAgICAgICAgICAgICAgICAgICBtb3YgICAgIGRzLCBheAogICAgICAgICAgICAgICAgICAgIG1vdiAgICAgd29yZCBwdHIgZHM6W1ZSQU1PRkZTRVQyXSwgdgoKICAgICAgICAgICAgICAgICAgICBwb3AgICAgIGJ4CiAgICAgICAgICAgICAgICAgICAgcG9wICAgICBkcwogICAgICAgICAgICAgICAgICAgIHBvcCAgICAgYXgKZW5kbQoKOy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAgICAgICAgICAgZG9zc2VnCiAgICAgICAgICAgIC5tb2RlbCAgICAgIHRpbnkKCkxGICAgICAgICAgIGVxdSAgICAgICAgIDBhaApDUiAgICAgICAgICBlcXUgICAgICAgICAwZGgKVEFCICAgICAgICAgZXF1ICAgICAgICAgMDloClNQQUNFICAgICAgIGVxdSAgICAgICAgIDIwaAoKICAgICAgICAgICAgLmNvZGUKICAgICAgICAgICAgb3JnICAgICAgICAgMDAyY2gKZW52c2VnICAgICAgbGFiZWwgICAgICAgd29yZAoKICAgICAgICAgICAgb3JnICAgICAgICAgMDA4MWgKY21kdGFpbCAgICAgbGFiZWwgICAgICAgYnl0ZQoKICAgICAgICAgICAgb3JnICAgICAgICAgMDEwMGgKCjstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KOyByZWdpZGVudC1hbCBwYXJ0CmVudHJ5OiAgICAgIGptcCAgICAgICAgIG1haW4KCklEICAgICAgICAgIGRiICAgICAgICAgICdVTkNBUFMnCklEX2xlbiAgICAgIGVxdSAgICAgICAgICQgLSBJRAoKb2xkMDkgICAgICAgbGFiZWwgICAgICAgZHdvcmQKb2xkMDlfb2ZmICAgZHcgICAgICAgICAgPwpvbGQwOV9zZWcgICBkdyAgICAgICAgICA/CgpvbGQyZiAgICAgICBsYWJlbCAgICAgICBkd29yZApvbGQyZl9vZmYgICBkdyAgICAgICAgICA/Cm9sZDJmX3NlZyAgIGR3ICAgICAgICAgID8KCmluMDlmbGFnICAgIGRiICAgICAgICAgIDAKZnVuY19ubyAgICAgZGIgICAgICAgICAgPyAgICAgICA7IOS9v+eUqOOBmeOCi+ODleOCoeODs+OCr+OCt+ODp+ODs+eVquWPtwoKOy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQo7IGludCAwOWggaGFuZGxlcgoKCktiUmVjZWl2ZURhdGEgICAgICAgcHJvYyAgICBuZWFyCiAgICAgICAgICAgICAgICAgICAgbW92ICAgICBjeCw4MDAwSApSZHlDaGVja0xvb3A6CiAgICAgICAgICAgICAgICAgICAgaW4gICAgICBhbCwwMDQzSAogICAgICAgICAgICAgICAgICAgIHRlc3QgICAgYWwsMDJICiAgICAgICAgICAgICAgICAgICAgam56ICAgICBSZWFkeQogICAgICAgICAgICAgICAgICAgIGxvb3AgICAgUmR5Q2hlY2tMb29wCiAgICAgICAgICAgICAgICAgICAgc3RjCiAgICAgICAgICAgICAgICAgICAgcmV0ClJlYWR5OgogICAgICAgICAgICAgICAgICAgIG1vdiAgICAgZHgsMDA1RkgKICAgICAgICAgICAgICAgICAgICBtb3YgICAgIGN4LDE4SApSZWNlaXZlTG9vcDoKICAgICAgICAgICAgICAgICAgICBvdXQgICAgIGR4LGFsCiAgICAgICAgICAgICAgICAgICAgbG9vcCAgICBSZWNlaXZlTG9vcAo7CiAgICAgICAgICAgICAgICAgICAgaW4gICAgICBhbCwwMDQzSAogICAgICAgICAgICAgICAgICAgIGFuZCAgICAgYWwsMzhICiAgICAgICAgICAgICAgICAgICAgam56ICAgICBSZWNlaXZlRXJyb3IKICAgICAgICAgICAgICAgICAgICBtb3YgICAgIGFsLDAwMDEwMTEwQgogICAgICAgICAgICAgICAgICAgIG91dCAgICAgMDA0M0gsYWwKICAgICAgICAgICAgICAgICAgICBtb3YgICAgIGN4LDAwMDdICkBAV2FpdExvb3AzOiAgICAgICAgb3V0ICAgICBkeCxhbAogICAgICAgICAgICAgICAgICAgIGxvb3AgICAgQEBXYWl0TG9vcDMKICAgICAgICAgICAgICAgICAgICBpbiAgICAgIGFsLDAwNDFICiAgICAgICAgICAgICAgICAgICAgY2xjCiAgICAgICAgICAgICAgICAgICAgcmV0ClJlY2VpdmVFcnJvcjoKICAgICAgICAgICAgICAgICAgICBtb3YgICAgIGFsLDAwMDEwMTAwQgogICAgICAgICAgICAgICAgICAgIG91dCAgICAgMDA0M0gsYWwKICAgICAgICAgICAgICAgICAgICBtb3YgICAgIGN4LDAwMDdICkBAV2FpdExvb3A0OiAgICAgICAgb3V0ICAgICBkeCxhbAogICAgICAgICAgICAgICAgICAgIGxvb3AgICAgQEBXYWl0TG9vcDQKICAgICAgICAgICAgICAgICAgICBpbiAgICAgIGFsLDAwNDFICiAgICAgICAgICAgICAgICAgICAgc3RjCiAgICAgICAgICAgICAgICAgICAgcmV0CktiUmVjZWl2ZURhdGEgICAgICAgZW5kcAoKS0JTZW5kQ29tbWFuZCAgICAgICBwcm9jICAgICAgICBuZWFyCjtpbnB1dCByZWdpc3Rlci1haApTZW5kUmV0cnk6CiAgICAgICAgICAgICAgICBtb3YgICAgIGFsLDAwMDEwMTExQgogICAgICAgICAgICAgICAgb3V0ICAgICAwMDQzSCxhbAogICAgICAgICAgICAgICAgbW92ICAgICBkeCwgMDA1RkgKICAgICAgICAgICAgICAgIG1vdiAgICAgY3gsIDAwMDdICkBAV2FpdExvb3AxOgogICAgICAgICAgICAgICAgb3V0ICAgICBkeCwgYWwKICAgICAgICAgICAgICAgIGxvb3AgICAgQEBXYWl0TG9vcDEKCiAgICAgICAgICAgICAgICBtb3YgICAgIGFsLCBhaAogICAgICAgICAgICAgICAgb3V0ICAgICAwMDQxSCwgYWwKICAgICAgICAgICAgICAgIG1vdiAgICAgY3gsIDAwMDdICkBAV2FpdExvb3AyOgogICAgICAgICAgICAgICAgb3V0ICAgICBkeCwgYWwKICAgICAgICAgICAgICAgIGxvb3AgICAgQEBXYWl0TG9vcDIKOwogICAgICAgICAgICAgICAgbW92ICAgICBhbCwgMDAwMTAxMTBCCiAgICAgICAgICAgICAgICBvdXQgICAgIDAwNDNILCBhbAo7CiAgICAgICAgICAgICAgICBtb3YgICAgIGJsLCAwMEgKQWNrUmV0cnk6CiAgICAgICAgICAgICAgICBjYWxsICAgIEtiUmVjZWl2ZURhdGEKICAgICAgICAgICAgICAgIGpjICAgICAgVGltZU91dAogICAgICAgICAgICAgICAgY21wICAgICBhbCwgMGZhSAogICAgICAgICAgICAgICAgam5lICAgICBOb3RBY2sKICAgICAgICAgICAgICAgIGNsYwogICAgICAgICAgICAgICAgcmV0Ck5vdEFjazoKICAgICAgICAgICAgICAgIGNtcCAgICAgYWwsMEZDSAogICAgICAgICAgICAgICAgamUgICAgICBTZW5kUmV0cnkKICAgICAgICAgICAgICAgIGluYyAgICAgYmwKICAgICAgICAgICAgICAgIGNtcCAgICAgYmwsIDA0SAogICAgICAgICAgICAgICAgam5lICAgICBBY2tSZXRyeQpUaW1lT3V0OgogICAgICAgICAgICAgICAgc3RjCiAgICAgICAgICAgICAgICByZXQKS0JTZW5kQ29tbWFuZCAgIGVuZHAKCkNBUFNXT1JLICAgIGVxdSAgICAgICAgIDA1M2FoCgpTZW5kODI1MUNhcHNPZmYgICAgIHByb2MgICAgICAgIG5lYXIKO2luaGliaXQga2IgaW50ZXJydXB0CjtEZWJ1Z1ZSQU1PdXQgICAgJ0QnCiAgICAgICAgICAgICAgICAgICAgb3IgICAgICAgICAgYWwsIDAyaAogICAgICAgICAgICAgICAgICAgIG91dCAgICAgICAgIDAwMDJoLCBhbAo7c2VuZCA5ZCBmb3IgTEVECjtEZWJ1Z1ZSQU1PdXQgICAgJ0UnCiAgICAgICAgICAgICAgICAgICAgbW92ICAgICAgICAgYWgsIDlkaAogICAgICAgICAgICAgICAgICAgIGNhbGwgICAgICAgIEtCU2VuZENvbW1hbmQKICAgICAgICAgICAgICAgICAgICBqYyAgICAgICAgICBAQHNlbmRfZW5kCjsKO0RlYnVnVlJBTU91dCAgICAnRicKICAgICAgICAgICAgICAgICAgICBtb3YgICAgICAgICBheCwgMDAwMGgKICAgICAgICAgICAgICAgICAgICBtb3YgICAgICAgICBkcywgYXgKICAgICAgICAgICAgICAgICAgICBtb3YgICAgICAgICBhaCwgZHM6W0NBUFNXT1JLXQogICAgICAgICAgICAgICAgICAgIHNobCAgICAgICAgIGFoLCAxCiAgICAgICAgICAgICAgICAgICAgYW5kICAgICAgICAgYWgsIDA4aAogICAgICAgICAgICAgICAgICAgIG9yICAgICAgICAgIGFoLCA3MGgKICAgICAgICAgICAgICAgICAgICBjYWxsICAgICAgICBLQlNlbmRDb21tYW5kCkBAc2VuZF9lbmQ6CjtEZWJ1Z1ZSQU1PdXQgICAgJ0cnCiAgICAgICAgICAgICAgICAgICAgbW92ICAgICAgICAgYWgsIDAzSAogICAgICAgICAgICAgICAgICAgIGludCAgICAgICAgIDE4SAoKO0RlYnVnVlJBTU91dCAgICAnSCcKICAgICAgICAgICAgICAgICAgICBjbGkKICAgICAgICAgICAgICAgICAgICBpbiAgICAgICAgICBhbCwgMDAwMkgKICAgICAgICAgICAgICAgICAgICBhbmQgICAgICAgICBhbCwgTk9UIDAySAogICAgICAgICAgICAgICAgICAgIG91dCAgICAgICAgIDAwMDJILGFsCiAgICAgICAgICAgICAgICAgICAgc3RpCjtEZWJ1Z1ZSQU1PdXQgICAgJ0knCjt3YWl0IDUwbXMKICAgICAgICAgICAgICAgICAgICBtb3YgICAgICAgICBkeCwgMDA1ZmgKICAgICAgICAgICAgICAgICAgICBtb3YgICAgICAgICBjeCwgMTAwMGgKQEB3YWl0bG9vcDoKICAgICAgICAgICAgICAgICAgICBvdXQgICAgICAgICBkeCwgYWwKICAgICAgICAgICAgICAgICAgICBsb29wICAgICAgICBAQFdhaXRsb29wCjtEZWJ1Z1ZSQU1PdXQgICAgJ0onCiAgICAgICAgICAgICAgICAgICAgcmV0ClNlbmQ4MjUxQ2Fwc09mZiAgICAgZW5kcAoKQ0FQU01BU0sgICAgZXF1ICAgICAgICAgMDJoClZSQU1PRkZTRVQgIGVxdSAgICAgICAgIDIgKiAoODAgKiAyNCArIDc5KQoKbXlpbnQwOQkJcHJvYwkJZmFyCgoJCQljbXAJCQljczppbjA5ZmxhZywgMAoJCQlqbmUJCQlAQG5vcDA5CgkJCWluYwkJCWNzOmluMDlmbGFnCgkJCQogICAgICAgICAgICBwdXNoZgoJCQljYWxsCQljczpbb2xkMDldCgoJCQlwdXNoCQlheAoJCQlwdXNoCQlkcwogICAgICAgICAgICBwdXNoICAgICAgICBkeAogICAgICAgICAgICBwdXNoICAgICAgICBjeAogICAgICAgICAgICBwdXNoICAgICAgICBieAoKRGVidWdWUkFNT3V0ICAgICdBJwoJCQltb3YJCQlheCwgMDAwMGgKCQkJbW92CQkJZHMsIGF4CgkJCW1vdgkJCWFsLCBkczpbQ0FQU1dPUktdCiAgICAgICAgICAgIGFuZCAgICAgICAgIGFsLCBDQVBTTUFTSwogICAgICAgICAgICBtb3YgICAgICAgICBheCwgMEEwMDBoCiAgICAgICAgICAgIG1vdiAgICAgICAgIGRzLCBheAogICAgICAgICAgICBqbnogICAgICAgICAgQEBjYXBzb24KQEBjYXBzb2ZmOgogICAgICAgICAgICBqcCAgICAgICAgICBAQGNhcHNuZXh0CkBAY2Fwc29uOgoKRGVidWdWUkFNT3V0ICAgICdCJwogICAgICAgICAgICBjYWxsICAgICAgICBTZW5kODI1MUNhcHNPZmYKRGVidWdWUkFNT3V0ICAgICdDJwoKQEBjYXBzbmV4dDoKO2luc3RlZCBjYWxsIEtCIEJJT1MtcmVzZXQgaW50IDE4aC0wM2ggaW4gU2VuZDgyNTFDYXBzT2ZmCjsgICAgICAgICAgICBtb3YgICAgICAgICBheCwgMDAwMGgKOyAgICAgICAgICAgIG1vdiAgICAgICAgIGRzLCBheAo7ICAgICAgICAgICAgbW92ICAgICAgICAgYWwsIGRzOltDQVBTV09SS10KOyAgICAgICAgICAgIGFuZCAgICAgICAgIGFsLCBub3QgQ0FQU01BU0sKOyAgICAgICAgICAgbW92ICAgICAgICAgZHM6W0NBUFNXT1JLXSwgYWwKCiAgICAgICAgICAgIHBvcCAgICAgICAgIGJ4CiAgICAgICAgICAgIHBvcCAgICAgICAgIGN4CiAgICAgICAgICAgIHBvcCAgICAgICAgIGR4CgkJCXBvcAkJCWRzCgkJCXBvcAkJCWF4CgoJCQlkZWMJCQljczppbjA5ZmxhZwpAQG5vcDA5OgogICAgICAgICAgICBpcmV0Cm15aW50MDkJCWVuZHAKCjstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCm15aW50MkYJCXByb2MJCWZhcgoJCQljbXAJCQlhaCwgY3M6ZnVuY19ubwoJCQlqbmUJCQlAQGNoYWluCgkJCQoJCQljbXAJCQlhbCwgMDBoCgkJCWplCQkJQEBmMDAKCQkJY21wCQkJYWwsIDAxaAoJCQlqZQkJCUBAZjAxCgkJCWptcAkJCUBAZXhpdDJGCkBAZjAwOgoJCQltb3YJCQlheCwgY3MJCQk7cmV0dXJuIGFsPTBmZmgsIGVzOmRpPUlEc3RyaW5nCgkJCW1vdgkJCWVzLCBheAoJCQltb3YJCQlkaSwgb2Zmc2V0IElECgkJCW1vdgkJCWFsLCAwZmZoCgkJCWptcAkJCUBAZXhpdDJGCQk7YXggIT0gMDAwMGgKQEBmMDE6CgkJCW1vdgkJCWR4LCBjcwoKCQkJbW92CQkJYXgsIDM1MDloCgkJCWludAkJCTIxaAoJCQltb3YJCQlheCwgZXMKCQkJc3ViCQkJYXgsIGR4CgkJCWpuegkJCUBAZXhpdDJGCQk7YXggIT0gMDAwMGgKCQkJCgkJCW1vdgkJCWF4LCAzNTJmaAoJCQlpbnQJCQkyMWgKCQkJbW92CQkJYXgsIGVzCgkJCXN1YgkJCWF4LCBkeAoJCQlqbnoJCQlAQGV4aXQyRgkJO2F4ICE9IDAwMDBoCgkJCQoJCQltb3YJCQllcywgZHg7CQkJO2F4ID09IDAwMDBoCkBAZXhpdDJGOgoJCQlpcmV0CkBAY2hhaW46CgkJCWptcAkJCWNzOltvbGQyRl0KbXlpbnQyRgkJZW5kcAoKVFNSU0laRQkJZXF1CQkJJCAtIGVudHJ5ICsgMjU2Cgo7PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQo7aW5pdGlhbGl6ZQoKCQkJCS5kYXRhCm1zZ19zdGF5CQlkYgkJJ3VuY2FwIOOBjOW4uOmnkOOBl+OBvuOBl+OBny4nLCBDUiwgTEYsICckJwptc2dfcmVsZWFzZQkJZGIJCSd1bmNhcCDjgpLop6PmlL7jgZfjgb7jgZfjgZ8uJywgQ1IsIExGLCAnJCcKbXNnX25vdGV4aXN0CWRiCQkndW5jYXAg44Gv5bi46aeQ44GX44Gm44GE44G+44Gb44KTLicsIENSLCBMRiwgJyQnCm1zZ19hbHJlYWR5CQlkYgkJJ3VuY2FwIOOBr+OBmeOBp+OBq+W4uOmnkOOBl+OBpuOBhOOBvuOBmS4nLCBDUiwgTEYsICckJwptc2dfaG9va2VkCQlkYgkJJ3VuY2FwOiBJTlQgMDloLzJGaCDjga7jgYTjgZrjgozjgYvjgYzjg5Xjg4Pjgq/jgZXjgownCgkJCQlkYgkJJ+ino+aUvuOBp+OBjeOBvuOBm+OCky4nLCBDUiwgTEYsICckJwptc2dfZnVuY2Z1bGwJZGIJCSd1bmNhcDogSU5UIDJGaCDjgavmnKrkvb/nlKjjg5XjgqHjg7Pjgq/jgrfjg6fjg7PjgYzjgYLjgorjgb7jgZvjgpMuJwoJCQkJZGIJCUNSLCBMRiwgJyQnCgoJCQkJLmNvZGUKbWFpbgkJCXByb2MJCW5lYXIKCgkJCQltb3YJCQlzaSwgb2Zmc2V0IGNtZHRhaWwKCQkJCWNsZApAQGdldGFyZzoKCQkJCWxvZHNiCgkJCQljbXAJCQlhbCwgU1BBQ0UKCQkJCWplCQkJQEBnZXRhcmcKCQkJCWNtcAkJCWFsLCBUQUIKCQkJCWplCQkJQEBnZXRhcmcKCQkJCW1vdgkJCWFoLCBhbAkJOyBhaCA9IOW8leaVsOOBruacgOWIneOBruaWh+WtlwoJCQkJbG9kc2IJCQkJCTsgYWwgPSDlvJXmlbDjga7mrKHjga7mloflrZcKCQkJCWNtcAkJCWF4LCAnLXInCgkJCQlqZQkJCUBAcmVsZWFzZQpAQHN0YXk6CgkJCQljYWxsCQlUU1JjaGVjawoJCQkJamMJCQlAQHNraXAxCgkJCQlqbXAJCQlAQGFscmVhZHkKQEBza2lwMToKCQkJCWNhbGwJCWdldGZ1bmMKCQkJCWpuYwkJCUBAc2tpcDIKCQkJCWptcAkJCUBAZnVuY2Z1bGwKQEBza2lwMjoKICAgICAgICAgICAgICAgIG1vdiAgICAgICAgIGZ1bmNfbm8sIGFoCgkJCQltb3YJCQlheCwgMzUwOWgKCQkJCWludAkJCTIxaAoJCQkJbW92CQkJb2xkMDlfb2ZmLCBieAoJCQkJbW92CQkJb2xkMDlfc2VnLCBlcwoJCQkJCgkJCQltb3YJCQlheCwgMzUyZmgKCQkJCWludAkJCTIxaAoJCQkJbW92CQkJb2xkMkZfb2ZmLCBieAoJCQkJbW92CQkJb2xkMkZfc2VnLCBlcwoJCQkJCgkJCQltb3YJCQlkeCwgb2Zmc2V0IG15aW50MDkKCQkJCW1vdgkJCWF4LCAyNTA5aAoJCQkJaW50CQkJMjFoCgoJCQkJbW92CQkJZHgsIG9mZnNldCBteWludDJmCgkJCQltb3YJCQlheCwgMjUyZmgKCQkJCWludAkJCTIxaAoKCQkJCW1vdgkJCWVzLCBlbnZzZWcKCQkJCW1vdgkJCWFoLCA0OWgKCQkJCWludAkJCTIxaAoJCQkJCgkJCQltb3YJCQlkeCwgb2Zmc2V0IG1zZ19zdGF5CgkJCQltb3YJCQlhaCwgMDloCgkJCQlpbnQJCQkyMWgKCQkJCQoJCQkJbW92CQkJZHgsIChUU1JTSVpFICsgMTUpIC8gMTYKCQkJCW1vdgkJCWF4LCAzMTAwaAoJCQkJaW50CQkJMjFoCgpAQHJlbGVhc2U6CgkJCQljYWxsCQlUU1JjaGVjawoJCQkJamMJCQlAQG5vdGV4aXN0CgkJCQkKCQkJCW1vdgkJCWFoLCBmdW5jX25vCgkJCQltb3YJCQlhbCwgMDFoCgkJCQlpbnQJCQkyZmgKCQkJCW9yCQkJYXgsIGF4CgkJCQlqbnoJCQlAQGhvb2tlZAoJCQkJCgkJCQlwdXNoCQlkcwoKCQkJCWxkcwkJCWR4LCBlczpbb2xkMDldCTsgZHM6ZHggPD0gb2xkIHZlYwoJCQkJbW92CQkJYXgsIDI1MDloCgkJCQlpbnQJCQkyMWgKCQkJCQoJCQkJbGRzCQkJZHgsIGVzOltvbGQyZl0JOyBkczpkeCA8PSBvbGQgdmVjCgkJCQltb3YJCQlheCwgMjUyZmgKCQkJCWludAkJCTIxaAoKCQkJCXBvcAkJCWRzCgogICAgICAgICAgICAgICAgbW92ICAgICAgICAgYWgsIDQ5aAogICAgICAgICAgICAgICAgaW50ICAgICAgICAgMjFoCgoJCQkJbW92CQkJZHgsIG9mZnNldCBtc2dfcmVsZWFzZQoJCQkJbW92CQkJYWgsIDA5aAoJCQkJaW50CQkJMjFoCgkJCQkKCQkJCW1vdgkJCWF4LCA0YzAwaAoJCQkJaW50CQkJMjFoCgkJCQkKQEBhbHJlYWR5OgoJCQkJbW92CQkJZHgsIG9mZnNldCBtc2dfYWxyZWFkeQoJCQkJam1wCQkJQEBlcnJvcgpAQGZ1bmNmdWxsOgoJCQkJbW92CQkJZHgsIG9mZnNldCBtc2dfZnVuY2Z1bGwKCQkJCWptcAkJCUBAZXJyb3IKQEBub3RleGlzdDoKCQkJCW1vdgkJCWR4LCBvZmZzZXQgbXNnX25vdGV4aXN0CgkJCQlqbXAJCQlAQGVycm9yCkBAaG9va2VkOgoJCQkJbW92CQkJZHgsIG9mZnNldCBtc2dfaG9va2VkCkBAZXJyb3I6CgkJCQltb3YJCQlhaCwgMDloCgkJCQlpbnQJCQkyMWgKCQkJCW1vdgkJCWF4LCA0YzAxaAoJCQkJaW50CQkJMjFoCgptYWluCQkJZW5kcAoKOy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tClRTUmNoZWNrCQlwcm9jCQluZWFyCgkJCQltb3YJCQlhaCwgMGMwaApAQHRjX2xvb3A6CgkJCQlwdXNoCQlheAoJCQkJbW92CQkJYWwsIDAwaAoJCQkJaW50CQkJMmZoCgkJCQljbXAJCQlhbCwgMGZmaAoJCQkJcG9wCQkJYXgKCQkJCWpuZQkJCUBAdGNfbmV4dGZ1bmMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA7aWYgcmVzaWRlbnRlZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDtlczpkaT0idW5jYXBzIgoJCQkJbW92CQkJc2ksIG9mZnNldCBJRAoJCQkJbW92CQkJY3gsIElEX2xlbgoJCQkJY2xkCgkJCQlyZXB6CQljbXBzYgoJCQkJanoJCQlAQHRjX2ZvdW5kCkBAdGNfbmV4dGZ1bmM6CgkJCQlpbmMJCQlhaAoJCQkJam56CQkJQEB0Y19sb29wCkBAdGNfbm90Zm91bmQ6CgkJCQlzdGMKCQkJCXJldApAQHRjX2ZvdW5kOgoJCQkJbW92CQkJZnVuY19ubywgYWgKCQkJCWNsYwoJCQkJcmV0ClRTUmNoZWNrCQllbmRwCgo7LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KZ2V0ZnVuYwkJCXByb2MJCW5lYXIKCQkJCW1vdgkJCWFoLCAwYzBoCkBAZmNfbG9vcDoKCQkJCXB1c2gJCWF4CgkJCQltb3YJCQlhbCwgMDBoCgkJCQlpbnQJCQkyZmgKCQkJCWNtcAkJCWFsLCAwMGgKCQkJCXBvcAkJCWF4CgkJCQlqZQkJCUBAZmNfZm91bmQKCQkJCWluYwkJCWFoCgkJCQlqbnoJCQlAQGZjX2xvb3AKQEBmY19ub3Rmb3VuZDoKCQkJCXN0YwoJCQkJcmV0CkBAZmNfZm91bmQ6CgkJCQljbGMKCQkJCXJldApnZXRmdW5jCQkJZW5kcAoJCQkJZW5kCQkJZW50cnkKOwo7CjsgMjAxMS4wMy4xMyBiZXRhMDMKCg==