P\000\001Cu\000\000\014\037(\000\000b\0000\000\006\020\003\000\0000{\030\000\003\007Y@\000\030=L\000\001Cl`\000\014\036f\000\000av0\000\006\0173\000\0000|0\000\003\007c\000\000\030>\030\000\001Cq@\000\014\037\014\000\000ax`\000\006\0173\000\0000{\030\000\003\007Y@\000\030=L\000\001Cl`\000\014\036f\000\000av0\000\006\0173\000\0000{\030\000\003\007Y@\000\030=L\000\001Cl`\000\014\036f\000\000av0\000\006\0173\000\0000{\030\000\003\007Y@\000\030=\000\000\001Cl`\000\014\036f\000\000av0\000\006\0173\000\0000{\030\000\003\007Y@\000\030=L\000\001Cl`\000\014\037\014\000\000ax`\000\006\017F\000\0000|0\000\003\007c\000\000\030>\030\000\001Cl`\000\014\036f\000\000av0\000\006\0173\000\0000{\030\000\003\007Y@\000\030=L\000\001Cl`\000\014\036f\000\000av0\000\006\0173\000\0000{\030\000\003\007Y@\000\030=L\000\001Cl`\000\014\036f\000\000av0\000\006\017 \000\000P\000\002\000\001\000\0000\000\020\000\005\000\001@\0008\000\020\000\004@\001 \000,\000\014\000\003 \000p\000\036\000\010\000\000\000\000\031\010L\000\001HW`\000\014E>\000\000d#\020\000\006\"_\000\0002\025x\000\003\021/@\000\031\n|\000\001HW`\000\014E>\000\000d\014p\000\006 s\000\0002\025x\000\003\0207@\000\031\005\010\000\001HW`\000\014C\n\000\000d\031\020\000\006!I\000\0002\014H\000\003\020d@\000\031\006$\000\001H2 \000\014C\022\000\000d\031\020\000\006!I\000\0002\025x\000\003\021/@\000\031\n|\000\001HW`\000\014E>\000\000d+p\000\006\"_\000\0002\025x\000\003\021/@\000\031\n|\000\001H5`\000\014E>\000\000d+p\000\006\"_\000\0002\025x\000\003\021/@\000\031\n|\000\001HW`\000\014E>\000\000d+p\000\006\"_\000\0001a@\000\003\021/@\000\031\n|\000\001HW`\000\014E>\000\000d+p\000\006\034\n\000\0002\025x\000\003\021/@\000\031\007,\000\001HW`\000\014E>\000\000d+p\000\006\"_\000\0002\025x\000\003\021/@\000\031\n|\000\001HW`\000\014E>\000\000d+p\000\006!{\000\0002\020@\000\003\021/@\000\031\n|\000\001HW`\000\014B<\000\000d!\000\000\006\"_\000\0002\025x\000\003\016\003\000\000\031\n|\000\001H\035`\000\01482\000\000d&p\000\006\034\006\000\0002\025x\000\003\021\016@\000\031\n|\000\001G\002`\000\014E>\000\000d+p\000\006!\006\006\003\001@`0\030\014\006\003\001@`0\030\014\006\003\001\000@ \020\010\004\002\001\000@ \020\010\004\002\001\000@n3\000\000\006K9Rt<@\000\000\003\005\\\000\000\000\000ff \000\0068\000\000\0003@\000\000\003\034\000\000\000\031`\000\000\001N\000\000\000\014p\000\000\000g\000\000\000\0068\000\000\0003?@\000\003\033|\000\000\031_`\000\001M~\000\000\014op\000\000g\000\000\000\0068\000\000\0003@\000\000\003\034\000\000\000\031`\000\000\001N\000\000\000\014p\000\000\000g\000\000\000\0068\000\000\0003@\000\000\003\034\000\000\000\031`\000\000\001N\000\000\000\014p\000\000\000g\000\000\000\0068\000\000\0003@\000\000\003\034\000\000\000\031_`\000\001N\000\000\000\014p\000\000\000g\000\000\000\0068\000\000\0003@\000\000\003\034\000\000\000\031`\000\000\001N\000\000\000\014p\000\000\000g\000\000\000\0066^\000\0003@\000\000\003\034\014@\000\032\010L\000\001P@\000\000\r\003t\000\000g\024p\000\006B\014\000\0004\020\000\000\003!\011Cds%2Kv\021\033ae\023v\021u5\n9Le%\007\177(O%\034z%-nA\014|2/\035\007\006\000bC\022Xo!@\000i- \000\006I]\000\0004Mh\000\003$n@\000\032&t\000\001R7 \000\r\023:\000\000i\033P\000\006I]\000\0004Mh\000\003$n@\000\032&t\000\001R7 \000\r\023:\000\000i\033P\000\006I]\000\0004Mh\000\003$n@\000\032&t\000\001R7 \000\r\023:\000\000i\033P\000\006I]\000\0004Mh\000\003$n@\000\032&t\000\001R7 \000\r\023:\000\000i\033P\000\006I]\000\0004Mh\000\003$n@\000\032&t\000\001R7 \000\r\023:\000\000i\033P\000\006I]\000\0004T\000\000\003$n@\000\032&t\000\001R7 \000\r\023:\000\000i_ \000\006I]\000\0004Mh\000\003$n@\000\032&t\000\001R7 \000\r\033z\000\000i_P\000\006M}\000\0004oh\000\003&~@\000\0327t\000\001S? \000\r\033z\000\000i_P\000\006M}\000\0004Mh\000\003$n@\000\032&t\000\001R7 \000\r\023:\000\000i\033P\000\006I]\000\0004Mh\000\003$n@\000\032&t\000\001R8`\000\r\023:\000\000i\033P\000\006I]\000\0004Mh\000\003$n@\000\032&t\000\001R7 \000\r\033n\000\000i\033P\000\006I]\000\0004U\020\000\003$n@\000\032&t\000\001R7 \000\r\023:\000\000i\033P\000\006I]\000\0004Mh\000\003$n@\000\0327P\000\001R7 \000\r\023:\000\000i]0\000\006I]\000\0004Mh\000\003$n@\000\032&t\000\001R7 \000\r\023:\000\000i\033P\000\006Mg\000\0004N \000\003$n@\000\032&t\000\001R7 \000\r\033H\000\000i[P\000\006I]\000\0004Mh\000\003&m\000\000\032&t\000\001S3 \000\r\025&\000\000iXP\000\006I]\000\0004Mh\000\003&a\000\000\032&t\000\001S.`\000\r\023:\000\000i\033P\000\006Mt\000\0004gH\000\003&\023\000\000\0323d\000\001S\011@\000\r\030L\000\000iIp\000\006LH\000\0004d@\000\003&$\000\000\0322 \000\001S\022\000\000\r\031\020\000\000iI\000\000\006L=\000\0004ch\000\003&\023\000\000\0321\030\000\001S\011@\000\r\030L\000\000iD`\000\006L&\000\0004b0\000\003&\033\000\000\0321X\000\001S\r@\000\r\030l\000\000iF`\000\006L6\000\0004b0\000\003&\023\000\000\0321\030\000\001S\011@\000\r\030L\000\000iD`\000\006L&\000\0004b0\000\003&\023\000\000\0321\030\000\001S\011@\000\r\030L\000\000iD`\000\006L&\000\0004b0\000\003&\023\000\000\0321\030\000\001S\004`\000\r\030L\000\000iD`\000\006L&\000\0004b0\000\003&\023\000\000\0321\030\000\001S\011@\000\r\030L\000\000iF`\000\006L6\000\0004c0\000\003&\033\000\000\0321X\000\001S\r@\000\r\030L\000\000iD`\000\006L&\000\0004b0\000\003&\023\000\000\0321\030\000\001S\011@\000\r\030L\000\000iD`\000\006L&\000\0004b0\000\003&\023\000\000\0321\030\000\001S\011@\000\r\030L\000\000iD`\000\006L&\000\0004a\030\000\005\000\000\020\000\010\000\003\000\001\000\000(\000\014\000\003@\001\000\000$\000\n\000\002`\000`\000\032\000\007\000\001p\000@\000\000 PH4\"\025\014\000\000\030,&\033\021Jf\000\000\006\003\011Hf4\032MFsAd\000\000\000\000\000\000\000\000\000\000\000\000 \020\010\004\002\001",0x1151);
- private static final int[] _data4 = decodeData("\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006n]\000\0009Ah\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\r]>\000\000s\003P\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033;\004\000\001f\006`\000\000\000\000\000\000\000\000\000\000\000\000\000 \0006v\020\000\003L\014@\000\000\000\000\000\000\000\000\000\000\000\000\000@\000s\0130\000\007\030\021\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001f\026 \000\0160\036\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003L+@\000\034`4\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\007\030[`\0009A8\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\01613@\000s\002P\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034b_\000\001f\004`\000\000\000\000\000\000\000\000\000\000\000\000\000 \0009H\020\000\003L\031@\000\000\000\000\000\000\000\000\000\000\000\000\000@\000s\0170\000\007\0301\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001f `\000\0160j\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\00372\000\000\034aT\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006ne\000\0009B8\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\r]L\000\000s\004P\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\034d\020\000\001f\022 \000\000\000\000\000\000\000\000\000\000\000\000\000 \0009Gr\000\003L'@\000\000\000\000\000\000\000\000\000\000\000\000\000@\000s\017`\000\007\030M\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001f\0368\000\0161\026\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\0038-\000\000\034.l\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006p\\\000\0008]@\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\ra<\000\000q:P\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033C\000\000\001bt@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0009H(\000\003Eg@\000\011\034\000\000\000\000\000\027(\000\000\000\000\000$ \000\000\000\000\000\035 \000\000\000\000\001\016@\000\000\000\000\005u\000\000\000\000\000\0040\000\000\000\000\000\027T\000\000\000\000\000\021\030\000\000\000\000\000\036P\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\007\030t\000\0009F`\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\0161f\000\000s\rP\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034cH\000\001f\032aqjn:\032.Fc\025H>\000\000\000\0007\033\030\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003:6\000\000\000\002\020\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\007\031\004\000\000\000\004\"\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\0161|\000\000\000\010H\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033S4\000\000\000\021\030\000\000\000\000\000\000\000\000\000\000\000\000\000 \0007&p\000\000\000\002@\000\000\000\000\000\000\000\000\000\000\000\000\000@\000nMp\000\000\000E \000\000\000\000\000\000\000\000\000\000\000\000\001\000\001]\034\000\000\000\001\013\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003:8@\000\000\002\027\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006tr\000\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\rif\000\000\000@\014\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033SP\000\000\001\000(\000\000\000\000\000\000\000\000\000\000\000\000\000 \0007'(\000\000\002\000@\000\000\000\000\000\000\000\000\000\000\000\000\000@\000nN`\000\000\004\001@\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001]\035`\000\000\030\"\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003:<\000\000\0000T\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006ty\000\000\000QD\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\0162\000\000\000\001$\010\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033Sh\000\000\000A\030\000\000\000\000\000\000\000\000\000\000\000\000\000 \0007'X\000\000\001\002@\000\000\000\000\000\000\000\000\000\000\000\000\000@\000nO@\000\000\002\005 \000\000\000\000\000\000\000\000\000\000\000\000\001\000\001]\037 \000\000\004\013\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003:?\000\000\000\030\013\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006t\177\000\000\00006\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\rj\000\000\000\000a,\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033T\004\000\000\001CX\000\000\000\000\000\000\000\000\000\000\000\000\000 \0007(\020\000\000\003\010 \000\000\000\000\000\000\000\000\000\000\000\000\000@\000nP0\000\000\006\022`\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001]!\000\000\000\014-@\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003:B@\000\000\030k\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006u\006\000\000\0001v\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\rj\016\000\000\000d,\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033T \000\000\001IX\000\000\000\000\000\000\000\000\000\000\000\000\000 \0007(H\000\000\003\0250\000\000\000\000\000\000\000\000\000\000\000\000\000@\000nQ \000\000\006.`\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001]\"`\000\000\014u@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\003:F\000\000\000\031{\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006u\r\000\000\00036\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\rj\034\000\000\000f,\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033S0\000\000\000\020@\000\000\000\000\000\000\000\000\000\000\000\000\000 \0009H \000\000\000!\020\000\000\000\000\000\000\000\000\000\000\000\000\000@\000s\017`\000\000\000B@\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001]\033 \000\000\001\005@\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003:7\000\000\000\000\014\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006to\000\000\000\004\032\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\ri`\000\000\000\0108\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033SD\000\000\000\020x\000\000\000\000\000\000\000\000\000\000\000\000\000 \0007'\030\000\000\002\000 \000\000\000\000\000\000\000\000\000\000\000\000\000@\000nQp\000\000\002C`\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001]$\000\000\000\004\010\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003:H@\000\000\010\021\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\007\031\001\000\000\000B\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\rj$\000\000\000bh\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033TL\000\000\001GP\000\000\000\000\000\000\000\000\000\000\000\000\000 \0007) \000\000\003\033 \000\000\000\000\000\000\000\000\000\000\000\000\000@\000nRP\000\000\006>@\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001]%@\000\000\004\006@\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003:K@\000\000\010\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\006u\030\000\000\000\020$\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\0162\002\000\000\001\000H\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033Td\000\000\000B \000\000\000\000\000\000\000\000\000\000\000\000\000\000\0007)P\000\000\001\004P\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000nS0\000\000\002\005`\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001]'\000\000\000\000\014@\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003:N@\000\000\000\032\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006u\036\000\000\000\0006\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\rj>\000\000\000\000p\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033U\000\000\000\000\001h\000\000\000\000\000\000\000\000\000\000\000\000\000 \0007*\010\000\000\000\003`\000\000\000\000\000\000\000\000\000\000\000\000\000@\000nT \000\000\000\007`\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001](`\000\000\000\020\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003:R\000\000\000\010 \000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006u%\000\000\000\020B\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\rjL\000\000\000\001\004\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033U\034\000\000\000B\020\000\000\000\000\000\000\000\000\000\000\000\000\000 \0007*@\000\000\001\0040\000\000\000\000\000\000\000\000\000\000\000\000\000@\000s\020 \000\000\002\006\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001]* \000\000\004\014@\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003:U\000\000\000\010\032\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006u+\000\000\000\0206\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\rjX\000\000\000 p\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033U4\000\000\000Ah\000\000\000\000\000\000\000\000\000\000\000\000\000 \0007*p\000\000\001\003p\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000nUp\000\000\002\007@\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001]\033\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003LB\000\000\000\002\001\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\007\030~\000\000\000\004\004\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\riZ\000\000\000\010\014\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033S8\000\000\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000 \0007&x\000\000\000 P\000\000\000\000\000\000\000\000\000\000\000\000\000@\000nN\000\000\000\000A@\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001]\034 \000\000\001\003@\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003:G@\000\000\n\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\007\031\003\000\000\000\020\002\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\rj`\000\000\000 \010\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\034cl\000\000\000@\030\000\000\000\000\000\000\000\000\000\000\000\000\000 \0009Gd\000\000\001\000@\000\000\000\000\000\000\000\000\000\000\000\000\000@\000nV\020\000\000\002\001 \000\000\000\000\000\000\000\000\000\000\000\000\001\000\001],@\000\000\004\003\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003:Y@\000\000\014\007\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006u4\000\000\000\030\020\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\rjj\000\000\0000$\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033UX\000\000\000`P\000\000\000\000\000\000\000\000\000\000\000\000\000 \0007)\000\000\000\001\0010\000\000\000\000\000\000\000\000\000\000\000\000\000@\000nR\020\000\000\002\003\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001]-`\000\000\020\010\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003:\\\000\000\000 0\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006u9\000\000\000A \000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\rjt\000\000\001\003@\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033Ul\000\000\002\011\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \0007+`\000\000\004\026\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000nWP\000\000\0104\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001]/@\000\000\020x\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003:9@\000\000\020\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006tt\000\000\000 \002\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\rj~\000\000\000`\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033V\000\000\000\001@@\000\000\000\000\000\000\000\000\000\000\000\000\000 \0007,\010\000\000\003\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000nX \000\000\006\n\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001]0`\000\000\014\034\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003:b\000\000\000\030@\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006uE\000\000\0001\020\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\rk\014\000\000\000b`\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033V\034\000\000\001F\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \0007,@\000\000\003\r\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000nY\020\000\000\006\036\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001]2@\000\000\014D\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003:e@\000\000\031\n\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006uL\000\000\00020\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\rk\032\000\000\000dh\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033V8\000\000\001J@\000\000\000\000\000\000\000\000\000\000\000\000\000 \0007,x\000\000\003\025 \000\000\000\000\000\000\000\000\000\000\000\000\000@\000nZ\000\000\000\006.\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001]4 \000\000\014]\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003:i\000\000\000\031H\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006uS\000\000\0003\024\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\rk(\000\000\000f`\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033VT\000\000\001N@\000\000\000\000\000\000\000\000\000\000\000\000\000 \0007-0\000\000\003\035 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000nZp\000\000\006>\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001_\026`\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003L?@\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\006|]\000\000\000\000\006\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\rXB\000\000,\020\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033xL\000\000X\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \0009HR\000\0011\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000s\021 \000\002b\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001_E\000\000\005D\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003?\n@\000\013\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\007\031\005`\000\026\030\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\r|.\000\000,0\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033x`\000\000X`\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \0007qP\000\0012\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000oc0\000\002e\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001f\037`\000\005\n\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003?\016\000\000\n|\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006~\035\000\000\025x\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\r|>\000\000-P\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033y\000\000\000[ \000\000\000\000\000\000\000\000\000\000\000\000\000\000 \0009G\030\000\0016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000s\016@\000\002[\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001f\034@\000\005\\\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003L<@\000\013,\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006~\"\000\000\025H\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\r|F\000\000+\020\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033y\024\000\000V\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \0007r0\000\001,\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000oe\000\000\002^\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001_J@\000\005$\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003?\026@\000\n\020\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006l\r\000\000\0258\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\r|^\000\000,p\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033y@\000\000Y@\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \0009H\002\000\001+\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000of\020\000\002h\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001[W \000\005*\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\0037/@\000\nT\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006~2\000\000\025 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\0162\006@\000+P\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033/P\000\000W \000\000\000\000\000\000\000\000\000\000\000\000\000\000 \0007s\030\000\001)@\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000s\016\\\000\002S\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001_M\000\000\005T\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003L:@\000\013(\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006~5\000\000\025`\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\r|l\000\000+@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\033y`\000\000T \000\000\000\000\000\000\000\000\000\000\000\000\000\000 \0007sH\000\0014@\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000og0\000\002P\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001_O \000\005\034\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003?\037\000\000\n4\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006~?\000\000\024`\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\r}\002\000\000)0\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\034cp\000\000R@\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \0007t\030\000\001$@\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000ohP\000\002F\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001_Q@\000\005\014\000\000\000\000\000\000\000\006~Y\000\0007uX\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016*\022\000\000rT0\000\007\025=\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034\001P\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000Laj^4$4s\033;n`\000\n\000\005@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000r[\000\000\007\025X\000\0009-P\000\003Jm\000\000\034Vp\000\001e7\000\000\016+<\000\000r[`\000\007\025`\000\0009.\000\000\003Jq\000\000\034W\010\000\001e9\000\000\016+H\000\000r\\`\000\007\025f\000\0009.@\000\003Jt\000\000\034W(\000\001e:@\000\016+X\000\000r]@\000\007\025n\000\0009.p\000\003Jx\000\000\034W@\000\001e<@\000\016+d\000\000r^@\000\007\025t\000\0009/0\000\003J{\000\000\034W`\000\001e>\000\000\016+t\000\000r_ \000\007\025|\000\0009/`\000\003J\177\000\000\034Wx\000\001e@\000\000\016,\000\000\000r` \000\007\026\002\000\00090 \000\003K\002\000\000\034X\030\000\001eA@\000\016,\020\000\000ra\000\000\007\026\n\000\00090P\000\003K\006\000\000\034X0\000\001eC@\000\016,\034\000\000rb\000\000\007\026\020\000\00091\020\000\003K\011\000\000\034XP\000\001eE\000\000\016,,\000\000rb`\000\007\026\030\000\00091@\000\003K\r\000\000\034Xh\000\001eG\000\000\016,8\000\000rc`\000\007\026\036\000\00092\000\000\003K\020\000\000\034Y\010\000\001eH@\000\016,H\000\000rd@\000\007\026&\000\000920\000\003K\024\000\000\034Y \000\001eJ@\000\016,T\000\000re@\000\007\026,\000\00092p\000\003K\027\000\000\034Y@\000\001eL\000\000\016,d\000\000rf \000\007\0264\000\00093 \000\003K\033\000\000\034YX\000\001eN\000\000\016,p\000\000rg \000\007\026:\000\00093`\000\003K\036\000\000\034Yx\000\001eO@\000\016-\000\000\000rh\000\000\007\026B\000\00094\020\000\003K\"\000\000\034Z\020\000\001eQ@\000\016-\014\000\000ri\000\000\007\026H\000\00094P\000\003K%\000\000\034Z0\000\001eS\000\000\016-\034\000\000ri`\000\007\026P\000\00095\000\000\003K)\000\000\034ZH\000\001eU\000\000\016-(\000\000rj`\000\007\026V\000\00095@\000\003K,\000\000\034Zh\000\001eV@\000\016-8\000\000rk@\000\007\026^\000\00095p\000\003K0\000\000\034[\000\000\001eX@\000\016-D\000\000rl@\000\007\026d\000\000960\000\003K3\000\000\034[ \000\001eZ\000\000\016-T\000\000rm \000\007\026l\000\00096`\000\003K7\000\000\034[8\000\001e\\\000\000\016-`\000\000rn \000\007\026r\000\00097 \000\003K:\000\000\034[X\000\001e]@\000\016-p\000\000ro\000\000\007\026z\000\00097P\000\003K>\000\000\034[p\000\001e_@\000\016-|\000\000rp\000\000\007\027\000\000\00098\020\000\003KA\000\000\034\\\020\000\001ea\000\000\016.\014\000\000rp`\000\007\027\010\000\00098@\000\003KE\000\000\034\\(\000\001ec\000\000\016.\030\000\000rq`\000\007\027\016\000\00099\000\000\003KH\000\000\034\\H\000\001ed@\000\016.(\000\000rr@\000\007\027\026\000\000990\000\003KL\000\000\034\\`\000\001ef@\000\016.4\000\000rs@\000\007\027\034\000\00099p\000\003KO\000\000\034]\000\000\001eh\000\000\016.D\000\000rt \000\007\027$\000\0009: \000\003KS\000\000\034]\030\000\001ej\000\000\016.P\000\000ru \000\007\027*\000\0009:`\000\003KV\000\000\034]8\000\001ek@\000\016.`\000\000rv\000\000\007\0272\000\0009;\020\000\003KZ\000\000\034]P\000\001em@\000\016.l\000\000rw\000\000\007\0278\000\0009;P\000\003K]\000\000\034]p\000\001eo\000\000\016.|\000\000rw`\000\007\027@\000\0009<\000\000\003Ka\000\000\034^\010\000\001eq\000\000\016/\010\000\000rx`\000\007\027F\000\0009<@\000\003Kd\000\000\034^(\000\001er@\000\016/\030\000\000ry@\000\007\027N\000\0009[=z?bU*U*U*U\037lw\014-D]\022A\017|`307\r\000V(\000\001+K\034,bY\004\000\014t'\016\"ETY\177@\000\000\000\000\000\000\000\177i\020~jD!40?x\000\000\000\000\000\000\000_|\000\000\000\000\000\000\000\037F~!r\020\000:g\007\1778U\016`\000\000\000\003rR\\\013|\027;t!\177 \000\000\000\000\000\000\000\177U*U*U*U*?p\000\000\000\000\000\000\000\037}bT;\024W\002\177\020h\000\000\000\000\000\000\000\007|SxPJ\"S]s~6\014JIr;6)\177\"t0*#T\010\004\177U*U*\030y\031\032?m[6m[>W\177\037xf3\031Lf3\001P\001\000\000\000\000\000\000\000\007~v\034\023`\000\000\000\013qx_`\n\026`\037)\177]G\004w\007 \037ty\027\nQlR\\\013|\001R[C|\027cfY\037yEd\030\000\000\000\000\017|br\013}z\034{wb\002qB\014T\033\007\023s\030ni9/TM\001zw= q:&_D~\021+\032Ur.xX?30-A5z{\023\037q*U*U*U\037\020\000\000\000\000\000\000\000\000\007\177I\007vT \000\000\003nBha\r\030L3\011w!40FL\000\000\000w#\014bE`\033Af?r\027f\006n'\021\003\037x\000\000\000\000\000\000\000\016t1L(\\\000\000\000\007\027\\\0164%\020\0228\024\013@\000\000\000\000\000\000\001\177N\000\000\000\000\000\000\000\177R\000\000\000\000\000\000\000?x\000\000\000\000\000\000\000^j\037.Mz\0208j\017D\036tz{4Xq\007i\023y\037\000N\024USwh\003 \014rbY\001}-A6\005X\025\013\\\177%*U*U*U\030?p\000\000\000\000\000\000\000\037\034\000\000\000\000\000\000\000\020.\000\000\000\000\000\000\000\007|\000\000\000\000\000\000\000\004\001\000\000\000\000\000\000\000\001\177@\000\000\000\000\000\000\000\177p\000\000\000\000\000\000\000=rv'%V?*|\037\026\\^4(W\034uOXqo\r/1\177\037'rP\006@\031`X:S|\004\"\021\010D\037\n1\177\nU*U*U*$\177`\000\000\000\000\000\000\000?x\000\000\000\000\000\000\000_|\000\000\000\000\000\000\000\017}\022\017m(D\026F\007H\r\030L3\n\027\000{wMkKmX\n7\031|(~D(\006y\025\030~C\"6\036/\023\024\002?6[$,JX\006(\037eLO$\020\rV\033Ox\021\010D\"\020\177\036GoY)`t_^ZCxJp\017\031<\024~I|`&{FQQ\003 ~Wmr\037n\004\014*?A\011\\>K:\011\023\037jt\033PnfA\177\017zU*U*U*Xoc?\020y\010\000\0353@\000\000\000\001\000\000\000\000\002\r \000\000\000\000\000\000\000\003%7\007x/GM2~\033y\007H@\001k\034\036$\000\000\000\000\000\000\000\000\000sBP\000\007\023N\000\0009\034q\177\177\177\177p\000\010\000\000\000\001`pZ\007`\000\000\000\000\000\000\000\177x\000\000\000\000\000\000\000?i!tv\033=\006a\037qQ\"D-AHYOz4 M!\037<~g\177\000\000\000\000\000\000\000\004\001\020\000\000\000\000\000\000\002\0008\000\000\000\000\000\000\001\000\024\000\000\000\000\000\000\000?p\000\000\000\000\000\000\000\000\000\000\000\010\000\000\000\000\017~\000\000\000\000\000\000\000\010\002 \000\000\000\000\000\000\000\000\031H\000?p\000\000\005\177@\000\000\000\000\000\000\000\177`\000\000\000\000\000\000\000?x\000\000\000\000\000\000\000 |\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\027\177\000\000\000\000\000\000\000\004\016\177\177\177\177p\000\000\002\007@\000\000\000\000\000\000\000\177_\177\177rJ\001V*?p\000\000\003-?J5\037s\177\177|R@5J@\000jp\000\002\001",0x1df);
+ private static final int[] _data3 = decodeData("\022\\h6{UXd\020\033Mw!\001`a9\034lR\001\034Js\023KA \000\000\000\000)].\007\003=dt2Y\004\0063=dm0]\0162\003\005de\035\002A I\025f\n\005\000\000\000\001\025fI7\035L\026c%H ;\030-G+\024X 7\035-V\023\025d 4\\d\006s\025Na:\032.f)h@'\022\\drp(\000A!S(R\0014@t4\031$\004\n\r\032E\020\020n&{Mfa9\\lVk\011Xe9\010\014f{H@M:[\016FKAXe\020\021-g3%do7\033,VsQf\n\020\010\0106{Arr4Ym\007!\000PC\024H\006\023Idp-\031\014\006#!\001\032a9\030mr\002\011By2@\000\000\002QPi9H\r\027\031\001\002C&Q%B\003IJl2X.6)\000`.\034Md\002A\0114e6HE\022a\000b2\020\021LV\021\000d0\031\r\001\"\001\001 l0]\014f{IZ 4[LF+AJn2\031-g!\001le9\034m\026{8\\\000 PiT)\001Fo6Y.2\003]Rt4\010\010\024\022M\036L*U\010Tbd@N'H\nt\nI$A'\025\013\023Y\001Lo9\010\014F+QBi6\034d\007\023\025Bd\020\035\r\006)\001Pe6\034\004\0063%Xe\027\002D\002\002QPi9H\r\027\031\001Lr2Y$\007\033=Lt;X.&)0@a7\031\004\007K=j 0\\LR\003]Jl1[mV)\001ho\020\034LV#%ft9\032,'+QJ 4]\004\007+9He9\002D\002\003\rJr:\030-\026q\001Fo7\031\r\027#%^n9Nd\006\013L@o:]\rFK9Jd\020\032-b\003QPe\020\021ie)\001\016e7\031.&\0130@P:XMFK\014@L4XlVsMJ.\005\021\014V#%Fa:\031,B\003Q^ :\032\014R\003]Rs2\\nB\003\011Ji7\031d\004I\001Jv2\\D\006C\005H :\032\014R\003AXe0\\nW\023\024@o3\010\016&+\005Hi7\031a\"\001\001Do7Zn2\003=L \024\030nW\023IJn:\033\017\022\003M`e7\031\r\026s\034@s7[,R\003QRm2H\014F+\005H 3\033n\"\003QBx\020\034LV\013M^n9J%`RQPe\020\033LW;\025ft\020\035LW\023MRo7\010\0146\0138@b2H\014f{U\\d\020\030.B\003QPe\020\020(4j\024@h7[,W\003\005Ne\035\002D\002\003!ht8\016Er{M^u9\030lV3=dg2KMf+P^p\027X,6k\024Zc9\033n7\033\005fs\027BA%+MBg2NA&\013\rZe\020\026iu\002Q\022O'\013Ebrt@[#\022)D*t\\.\027\002A${Ahi7[N3P(@ \026Z\005B\0014Zh2[\016\002\001\000@ \020\010\004\002\001\000@ \020\010\004\002\001\001fh7]d\007#!Rs\020\032\014Vc@@a7\031\004\006+aRt\005\010\004\002k\030X \026K,f{IZa:\010\010dzI\032A*\010\004\002\001\000@ \020\034lW!\001^u:\034\016W!\001Li6\031$\0063=dm0]\001\"\001\000Zo\026\010\005Rk=jt3\032-F)\001\014I&\021$\002\001\000@ \020\010\004\007\033\025h 7].G\003Uh 3\032-F)\001\\a6Y!\"\001\000Zr\026\010\005RkIJp7\\NB\002\031\022L\"H\004\002\001\000@ \020\010\004\007\033\025h 9\031.\006{Ih 3\032-F)\001\\a6Y!\"\001\000Zl\026\010\005RkMrm1\033mFc%ft\020\021I\024b\024@ \020\010\004\007\033\025h 9^-V\023=X 6\032.7!\001Li6\031$\006s\005Ze\005\010\004\002\001\000@ \026K-F\013\011Jl2\035-W\001\000@ \020\010\004\002\001\000@ \020\n\rvc\020@n0[,R\003\031^r\020\013%W\033eZb7[\rFKMh)\005\010\004\002\001\000@ \026K.fK\rJl0XLVcL@F$S\010R\001\000@ \020\034lW!\001Li6\031$\006s\005Ze\020\031Mw\021\001Xa1\031-B\003\021jm8\010\r\026q\001,I!Q$\0063=dm0]\001\"\001\000@ \020\010\005RkMJt8\030d\0052\005\030U\"H\004\002\001\000@ \020\010\004\007\033\025h 8\034Mv;IBm\020\030mw+9he9\002D\002\001\000@ \020\013%V3I^m\026]\rr\002Y\002L*Q$\0052\005\030U\"H\0166+P@s:\030.'!\001Bn2\010\014Vs\020V1\020\033lb\003=jt8\035.B\003\031Rl2BD\002\001\000@ \020\013%V\033Aj !T\nR\001\000@ \020\010\004\002\001\000@ \020\010\0166+P@t0\\Lv+P@p9\033l6+Mfo9\002D\002\001\000@ \020\013%VK9Rt6Y-R\002Y\002L*Q$\002\001\000@ \020\010\014F+\031Rn2H\004v+5`t\000\000\004Vc\020@(\030\036\004Vc`R\000\022KF3\003\034\000\000\000\022-Fc\025Na6\023NVk\011Jr*\036.\006)T\000\000'\\\014W\023\005ho9\022.4s=hDs:\034M\026s\034P)\000\032.5{1Rs:\n\005\020\000\000\000i9Wmg+5De9\n\005\020\0031Jn\024\n \000\000\001Br1]\014\026q R\000\000\000\000\006\013IFc7\\e\002H\000\000\000\000\030.&\033MRn\024\n \000\000\000\000t0[E\002H\000\000\0001[n2A$\000\000\000\034m\026q R\000\000\000\014fc=Bt\024\n \006K9h(\024@\000\000\003\005Hd9\031.7\031 R\000\000\000\r\026s\021Jx4[Lp\000\000\000\0006\033lvK\rBl\020\033Mw \001`o;Y.\"\003=L\000\000\000\000\006s\025Na:\032-vp\000\000\000\000\033-v#UXo\000\000\r\026sQJg2\\D\006#%li9Z-vp\000\000\000\000\033.VcQRp6\032,6\013QRo7\000\000\007\033UDt9\030,7#%^n\000\030,F#%hi7[@\000\000\000\000l7Ym\026\033\005X 9Z\r\0263P@r4Ym\007 \001Br4]\r\006k\025hi1H\0166C%Lt\020\034M\026;!h\000\000\034m\006K\031h 6\031,g \000\000b0[M2\003\011rt2H\rv0\000\000\000\000\032\r\026; @b<]\014R\003=L\000\000\000\000\006c=n 1\036.F)\001^f\000\031n&+\005he9\010\016FC\005\\\000\000\000\000\006;IJa:\031.\"\003QPa7\010\rw\021\001Jq:X-@\000\000\000l2\\n2\003QPa7\000\000\000\0031Js9H\016FC\005\\ 7\\D\006+Eja6\000\000\007#\025ft\020\031Mw\021\001Rn2\\.V\0131Rt<@\016F+Mh 3\033n\"\003\025bu0[\r\027#d\000\000\000\033\rv;%Fa6\010\014\026s\020\000e<\030mG+MRv2H\rw\020\000\000\000\000\033\rv;%Fa6\010\rw\020\000\000a8\034\014Vs\020@t7H\rFKMh\000\000\033n\006+8@i7\031\014W@\000\000s:\030.'!\001Xi9]\000\000\0031Jf:\010\016\006\013IJn:\032\014W\033%f\000\000\000\000\007\033QBr:\010\rv1\001Jx8\034LW\033MRo7\000\014Vs\020@o3\010\014WCAde9\\m\026{8\000\000\000\000\000\024\177P\000\001(\010\000\000\nA\020\000\000S0@\000\005\032\030\000\000*\011\000\000\002Pj\000\000\024h \000\001'\016\000\000\n9P\000\000SS\000\000\005\036\024\000\000)t \000\002O8\000\000\024|p\000\001'r\000\000\n4\020\000\000S!\000\000\005\032\010\000\000)P@\000\002Sr\000\000\025\036\000\000\001+\007\000\000\nX8\000\000UJ\000\000\005-\010\000\000*K@\000\002T \000\000\025#\000\000\001*#\000\000\nV0\000\000U6@\000\005+P\000\000*^@\000\002V\002\000\000\025&p\000\001*P\000\000\nUX\000\000Tj\000\000\005&`\000\000+\024 \000\002Y\"\000\000\025J\020\000\001,Q\000\000\ne\010\000\000V(@\000\0052D\000\000+\024 \000\002Xt\000\000\025L\020\000\001,Y\000\000\neH\000\000V,@\000\0052d\000\000+\026 \000\002Y2\000\000\025G \000\001,:\000\000\nc0\000\000V\035\000\000\005k\\\000\000.c`\000\002un\000\000\027.p\000\001:w\000\000\013Zp\000\000]N\000\000\005hP\000\000.G \000\002tb\000\000\027'\000\000\001:?\000\000\013UH\000\000]8\000\000\005qh\000\000/\023\000\000\002y\"\000\000\027L\020\000\001r\000\000\013x \000\000_7@\000\005{<\000\000/Z`\000\002}V\000\000\027m0\000\001>k\000\000\013vX\000\000_5@\000\006\025l\000\0001\025 \000\003\011*\000\000\030JP\000\001E7\000\000\014+\030\000\000b*@\000\006\022T\000\0001\025 \000\003\011`\000\000\030M@\000\001DU\000\000\014(\000\000\000b*@\000\006\023p\000\0001\025 \000\003\011*\000\000\030JP\000\001DU\000\000\014%(\000\000b*@\000\006\022T\000\0001\025 \000\003\011*\000\000\030JP\000\001DU\000\000\014%(\000\000bR\000\000\006\024l\000\0000{@\000\003\011*\000\000\030JP\000\001DU\000\000\014%(\000\000b*@\000\006\022T\000\0001\025 \000\003\011*\000\000\030JP\000\001DU\000\000\014%(\000\000b*@\000\006\022T\000\0001\025 \000\003\011*\000\000\030JP\000\001DU\000\000\014%(\000\000b*@\000\006\022T\000\0001\025 \000\003\011*\000\000\030JP\000\001DU\000\000\014%(\000\000b*@\000\006\022T\000\0001\025 \000\003\n\010\000\000\030JP\000\001DU\000\000\014'@\000\000b*@\000\006\022T\000\0001\025 \000\003\011*\000\000\030JP\000\001DU\000\000\014%(\000\000b*@\000\006\022T\000\0001\025 \000\003\011*\000\000\030JP\000\001DU\000\000\014%(\000\000b*@\000\006\022T\000\0001\025 \000\003\011*\000\000\030JP\000\001DU\000\000\014%(\000\000b*@\000\006\022T\000\0001\025 \000\003\011*\000\000\030JP\000\001DU\000\000\014%(\000\000b*@\000\006\023P\000\0001G@\000\003\014\010\000\000\030@@\000\001F\000\000\000\014.@\000\000d\010@\000\006\030\020\000\0002\017\000\000\003\010\010\000\000\031\006p\000\001G3\000\000\014 \000\000c9@\000\006\037\020\000\0001\001\000\000\003\010\010\000\000\030@@\000\001D\004\000\000\014 \000\000b\002\000\000\006\020\020\000\0001\001\000\000\003\010\010\000\000\030@@\000\001D\004\000\000\014 \000\000b\002\000\000\006\026\020\000\0001\001\000\000\003\r^\000\000\030@@\000\001F\\\000\000\014 \000\000b\002\000\000\006\020\020\000\0001\001\000\000\003\010\010\000\000\030@@\000\001D\004\000\000\014 \000\000b\002\000\000\006\020\020\000\0001\001\000\000\003\010\010\000\000\030@@\000\001D\004\000\000\014 \000\000b\002\000\000\006\020\020\000\0001\001\000\000\003\010\010\000\000\030@@\000\001D\004\000\000\014 \000\000b\002\000\000\006\020\020\000\0001\001\000\000\003\010\010\000\000\030d`\000\001D\004\000\000\014 \000\000c\021\000\000\006:\\\000\0003G@\000\003\0342\000\000\031c`\000\001N\036\000\000\014qp\000\000g\017\000\000\006=H\000\0003G@\000\003\034<\000\000\031c`\000\001N\036\000\000\014|@\000\000g\025\005\033Qdi7\031d\006c\025\\g:\032\004\006KL@n7]\004\003\0118\000C7[Nf+Ihe2\010\016Fy\001Rn:\031,v+H@f7\\D\006\023%\\a9\036$\006c=Ni1H\rw\003\025da:\033n\"p\001\nx8\034LW\033MRo7\010\014FK\020@n7]\004\007\023\025hu9\033D\006\011\001\\u6XLW\0218\000T7[d\006k\005\\y\020\011e\00298\000\000\000\023Mr\003YBl:Y$\006;%le7\013@\004#%li9Z-vq\001Dy\020\036LW\023<\\\000\000\000\004W\032U\\k7\033nvq\001^p:\032-vq\000P-\026I.2I8\024\000\000\000\004W\032U\\k7\033nvq\001fw4]\0146A\000P-\022Xe\022p(\000\000\000\000\004W\0325Rs9Z-f9\000Js\027\002@\000\001\025f%9KA \000\001\nr9\033n\"\003%\\ !S\011\022\003\005dg:[,VsQf:\020\000\000\000\000\001\006h7\\lVq\001\006P*H\014F{\025f 7\033nB\003Mjp8\033n'!\001Xo7\031d\007\023\025Ni9]\014W\023L\\\0007\033-w\031Xj0\031\000\000\000\000\000l5\030L\000\000\000\000\0006\032Xf\003\020\000\000\0009\rFV\031@d\000\000\035fc+\014`2\000\000\006c)`b6\000\000\000\0031UFe\030\014@\000\001Pj0\031\000\000\000\000\001Z6\032@\01431QHt;\014@\0029Xj0\031\011eB\001\035\\m7\\fc)@d'\026\010\004s1Tb0\023K\004\0029Xjc\030\014Dra\000Nr\033\r,3\001HN,\020\011ns1UF0\031\011eB\001\034l5\034\014&b90@'\033\r,6)@d'\026\010\004s!T`2\023K\004\002;4l5\023K\004\002;\014l42\035\016c\021\034\000\000\000\000\010W\023I^r\035\010\011fy\001Ze6[n'I\001Lo9\010\014GK9Bm4Xd\006\023ULf2\\E`P\000\000\000\022[\014@\002\r^n;\031.'\033%^n\020\035\014\026\0231J 4[L6{5`l2]\014Rp\000\000\000\000\025-f[9^w7\010\014Vs\r^d4[Lrp\000\000\0008\031.@\003IBw\000\034l7\020\001\036b5\031,7\"!Bs'\035-FbQrp2@\000\000\002%Xl2Yl\026b\011Xo1ZjF+IZi7\030.F{H\000\000$[\rF+\035Bl&\033mw\002\005Xg7@\016vC%Xe\000\000\000\007+9hi6\000\000\000\002ABr9Z-f9\001fo:\\L6)\001Li6\031$\0029\025f'\005\000\000\000\002\031^u7\031\004\002;tN 4[N7#\025Bd\020\033lb\003\025\\d\026[lbk\031Rl2K@\000\000\0006[\030\033 \000\000\000\000\033-L-QZlf16@\000\000\000m63\031[ \000\000\0006[\031LMP\000\000\000\033-Lffh\000\000\000\022\\e\002+\020R \035\010\004W\031\025f%9H\005\002+L@%9J'\"\001\025f\n\000\000\000\000\002MJr4[nW\031\001Jr9\033n \000\000\000%9I.2+L@-\020\021M\026c\024@%9K\004\006c%\\e\020\011,B\001 Js\020\011.2Ih@%9B@\000\002\025dr7\\@\000\000\001.a9\033M\026s\034\000I7\031Mp\000\000\000\000\"\031,'+\034\000\000\000\023\014\026\023\025X 7\030-V)\001\\o:\010\r\026q\001Xe3\035\rV{Mh 1[mG+5\\.\000\000\n7K5Do6\010\rf\0135J 9]\014\027\023Qf ;Z.FA\001B 9Z\r\0263PZs8\030,6)\001Fh0\\L\026\033QJr\027\000\000\000\000\001\004u3H\r\026q\001\002C&Q%B\003\r^d2H\014f{1Xo;\\`\000\000\000P0<\011/\003Q$\000I6\033\014V;\005XN:[,&+I(y8\031&\000\000\001\022l6\031,v\0131\036b5\031,7\"Qrp2@\000\000\000\000\004\010h\000\000 \\\020\000\002\005a\000\000\020.\010\000\001\002p@\000\010\027\004\000\000A8 \000\004\013B\000\000 \\\020\000\002\005a\000\000\020\"p\000\001\002p@\000\010\027\004\000\000A8 \000\004\013B\000\000 \\\020\000\002\005a\000\000\020.\010\000\001\002p@\000\010\027\004\000\000A8 \000\004\013B\000\000 \\\020\000\002\005a\000\000\020.\010\000\001\002p@\000\010\027\004\000\000A8 \000\004\013B\000\000 \\\020\000\002\005a\000\000\020.\010\000\001\002\025\000\000\010\027\004\000\000A8 \000\004\013B\000\000 \\\020\000\002\005a\000\000\020.\010\000\001\002p@\000\010\027\004\000\000A8 \000\004\013\002\000\000 Y\020\000\002\005a\000\000\020%x\000\001\002&\000\000\010\027\004\000\000A8 \000\004\013B\000\000 \\\020\000\002\005a\000\000\020.\010\000\001\002p@\000\010\027\004\000\000A8 \000\004\013B\000\000 \\\020\000\002\005a\000\000\020.\010\000\001\002p@\000\010\027\004\000\000A8 \000\004\013B\000\000 I@0\000\000\000\000\000\000\000\000\000\010\004\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000 \000\000\004\000\000\001\002\001\000@ \020\010\004\002\001\000@\010\004\000\000\000\000\000\000p8\034\016\007\003A`p8\034\016\007\003A`p8\034\016\007\003A`p8\034\016\007\000\000\000\000\000\030\000\006\003\001@`0\030\014\006\003\001@`0\030\014\006\003\001@`0\030\014\006\003\001@`0\000\000\000@\000\000`0\030\014\006\003\001@`0\030\014\006\003\001@`0\030\014\006\003\001@`0\030\014\006\003\001@`0\030\014\006\003\001@`0\030\014\006\003\001@`0\030\014\006\003\001@`0\030\014\006\003\001@`0\030\014\006\003\001@`0\030\014\006\003\001@`0\030\014\006\003\001@`0\030\014\006\003\001@`0\030\014\006\003\001@`0\030\014\006\003\001@`0\030\014\006\003\001@`0\030\014\006\003\001@`0\030\014\006\003\001@`0\030\014\006\003\001@`0\n7K9ha<\010\014W\023I^r\027\000\000\000\002Mrm1\033mB\003\005Xr2X,GI\001He3\032-f+\020\\\000(\034Mv;IBm\020\030mw+9he9\010\016Vs\021Jf4[LV!8\000\000'\035-V\023\025d 2\033lW\031\001\\o:\010\014fKP@i7\010\006#!\001Di:\034e`\0029jm1\031.\"\003\021^e9H\rf{P@f4]\004\006K8@1\033\010\014&KQf.\000\023NVk\011Jr\020\031\rv+L@n7]\004\0063%h 4[D\003A\001Di:\034e`\000\001\034u6XLW\021\001^u:\010\rv1\001da7\031lRp\000\000\000\000\021Mw+9H 2[LBk=L-3\032-F)\001Rn9]\014V\013\020@o3\010\004wi\034\\\000\000\000\011w+P@o3\010\rV+5^r\000\000\000\000\021LX\000\001\014E\000\000\010e\020\000\000F\031 \000\0044H\000\000##`\000\002\031{\000\000\021DH\000\001\014z@\000\010g<\000\000G= \000\0049t\000\000#R@\000\002\036\031\000\000\021n\030\000\001\016n@\000\010uh\000\000G\025`\000\004;^\000\000#]\020\000\002!p\000\000\022\0108\000\001\020P@\000\011\011\024\000\000HG`\000\004CT\000\000$\030p\000\002 k\000\000\022\021H\000\001\021\011@\000\011&X\000\000J\r`\000\004Q\"\000\000%\024p\000\002)!\000\000\022IX\000\001\024<\000\000\011 P\000\000J@\000\000\004St\000\000%j0\000\002-\014\000\000\022j0\000\001\027\022\000\000\0118t\000\000KE@\000\004[f\000\000%M\020\000\002-l\000\000\022w@\000\001\032a\000\000\011P|\000\000M\016 \000\004j\032\000\000&Pp\000\0025\001\000\000\023%p\000\001\031~\000\000\011Up\000\000M9@\000\004s\014\000\000'\0040\000\0028=\000\000\023I\010\000\001\034E@\000\011d\024\000\000N\030@\000\004p\000\000\000'\030\000\000\0029j\rw\023%Ni7\030-@\000\000\000\0002\031,fK9Rt4[m`\000\001(o7H\014F+\025`l\000\000*'p\000\002R5\000\000\025\022X\000\001(n@\000\nEX\000\000U\000`\000\0055\020\000\000+40\000\002[\035\000\000\025^\030\000\001-\037\000\000\nhx\000\000VE\000\000\0054\024\000\000+\033\000\000\002Y8\000\000\025Y\000\000\0011\017\000\000\013\006|\000\000X6@\000\005C\036\000\000,\030`\000\002a'\000\000\026\011p\000\0010J@\000\013\003\014\000\000X\021\000\000\005EJ\000\000-\023`\000\002h_\000\000\026EP\000\0014'@\000\013\"\030\000\000Z\011`\000\005P<\000\000-\002P\000\002gc\000\000\026< \000\0014r@\000\013A\020\000\000[y\000\000\005_<\000\000-z \000\002oH\000\000\026z@\000\0017O\000\000\013W\000\000\013u\024\000\000_'\000\000\005yT\000\000/I0\000\002~l\000\000\030*X\000\001B6\000\000\014\023\034\000\000a\027\000\000\006\011&\000\0000F@\000\003\004+\000\000\030\"\020\000\001Ax\000\000\014\016D\000\000a<@\000\006\030V\000\0001=@\000\003\013g\000\000\030]`\000\001Ei@\000\014-P\000\000bj`\000\006\026D\000\0001.\000\000\003\nQ\000\000\030g\020\000\001IX@\000\014KH\000\000d[ \000\006%D\000\0002+\020\000\003\022:\000\000\031\023\010\000\001I\024\000\000\014GX\000\000d5`\000\006'p\000\0003$@\000\003\031e\000\000\031N\000\000\001Lj@\000\014f0\000\000f+ \000\0062H\000\0003\0230\000\003\030i\000\000\031DP\000\001M5E+MRn3H\rw3\025ds4^LV!\001Bd2\034LW\033MRn3H\rV{\021J.\000\000\000\000\002\r U\020\031\rv+L@n7]\004\007\033U`p7\\NB\003QPi9H\014\026#\021de9\\m\026s\034@m7Y\014R\003\031^r\020\035\r\006KL@m7\031-V{9Rc\027\000\000\000\000\000\000\000\000\000\033@\000\000\000\000\000\000\000\r`\000\000\000\000\000\017@\003p\000\000\000\010`\017`\000\000\000\000\000\r@\0030\000l\000\000\000\002\020\000\000\000\000\000\000\000\000\000\000L\000\000\000\004`\000\000\\&\000\000\000\001\000\000\000\000\010\000\000\001\010@\000\000\027\000\000\000\000D\000\000\000\000\000\000\000\000\000\000\000\000\000\005zl\000\000\000\000\000\000\000\000\000\000\000\000\0114n,\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000.`\011X\002<\000\000\000\000\000\000\000\000\036\013\017FerY|v^-\000\000\000\000\000\000\000\000\000\003aP\000\000\000\000\000\000\000\002)\013J7Zmv[}v\177=@\000\000\000\001\036:\000\n@\000\000\000\000]@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001`P\000\024\016\000\000\000\000\000\000\000\000\000\000\000\000\0028\000\000\000\000\000\0008\014.\023\023Hfs\032Y$W)YL'3H,\022\013\004Ba\022\035\006G!QH$2\011Nc3Xnw\033]f\006\001\003A$qH\000\"2`\rfRV\000~\000\0350\000\000\000\000\001\000\000\000\000\003h\000\000\000\000\000\000\000\000\000\000\003\000@\000\020\030\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001 Q0\034\000\004$\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\003\005#z\000\014 \006\013D\000\005Rm<\\\002\000\000Ub`\000\000\000\0002!\002E$S(\000\000\000\000\000\000\000\000\000\000\000\000\000\003P\0004\000\000\000\0100\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016T\000\030\000\000\000\000\000\000\000\000\000\000\000\000\000\000H\000\000\000\000\000\003\020\000\000\000\000\000\n \000\000\000\000\000\034@\000\000\000\000\000I\000\000\000\000\000\0012\000\000\000\000\000\003$\000\000\000\000\000\007H\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\011\004@\000\000\000\0002\031\000\000\000\000\001$R\000\000\000\000\003Id\000\000\000\000\011\024H\000\000\000\000\026+\020\000\000\000\0004Z \000\000\000\000y<@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0018\000\000\000\000\000\006p\000\000\000\000\000\025`\000\000\000\000\000;@\000\000\000\000\001\027\000\000\000\000\000\002n\000\000\000\000\000\006\\\000\000\000\000\000\0178\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\003@\000\001\020\000\000'\000\000\006 \000\001\016\000\000\024@\000\003\034\000\0009\000\000\0108\000\001\022\000\000\024p\000\002d\000\0001`\000\006H\000\000s@\000\017\020\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000L\000\000\000\000\000\003\030\000\000\000\000\000\n0\000\000\000\000\000\034`\000\000\000\000\000I`P \000\000\0013q8\\ \000\003&\000\000\000\000\000\007L\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000`\000\000\000\000\000\021@\000\000\000\000\000C\000\000\000\000\000\001F\000\000\000\000\000\004\014\000\000\000\000\000\n\030\000\000\000\000\000\0300\000\000\000\000\0008`\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000H$\000\000\004@\003\021H\000\000\031\000\n%\020\000\000R\000\034N \000\001d\000I$@\000\004H\0012Y\000\000\013\020\003%R\000\000\032 \007Kd\000\000\037\017D\000\000\011Lj7\030\002gSyd`\000\000\004\002\001\000@ \002\011\004B!\020@\010\024\n\005\002A\000\030,\026\013\005B\000@`0\030\014\004\001!Ph4\032\010\003\003A`p8\020\007\007Capx \000\000\014FC1`t<\037\014\000\000\000\006 \001H\0002\000\014@\003\020\000\000\0009\000\016 \003H\000r\000\034@\000\000\002d\000Y\000\026 \005H\0012\000\000\000\017\020\003d\000y\000\036 \007H\000\000\000L@\023\020\004d\001\031\000& \000\000\002r\000\\@\027\020\005d\0019\000. \rH\0032\000l@\033\020\006d\000\000\000> \017H\003r\000|@\037\020\000\000\000\000\000\006`\003X\0016\000=@\000\011=~o[\000>`\011x\000\000\000\016E \000\000t*\000\017G\"P\000\000:\025\000\000\003Q(\000\000\000\000\000\000\003iT\000\000\036M \003ytj\000\000\017&P\000\000z5\000\000\000\000\000\000\000]*@\000\005jT\000_.U \000\002u*\000\000\027*P\000\000\000\000\000\000\017W(\000\000}:@\017wkT\000\000>] \000\003uj\000\000\000\000\000\000\002;\025\000\000\023Y(\002?\035J@\000\011lT\000\000Ne \000\000\000\000\000\000/6P\000\002{5\000/w[(\000\001=Z@\000\013mT\000\000^m \000\006w*\000\0007:P\006\177;U\000\000\033](\000\001]j@\000\000\000\000\000\000~} \000\007wj\000\177\177>P\000\003{u\000\000\037_(\000\000\000\000\000\000\000\000\000\000\000\017E`\000\001|n\000\000\027jp\000\001~w\000\000\000\000\000\000\000\000\000\000\000\r~\\\000\000\177}`\000\000\000\000\000\000\003 P\000\000\032\005\000\003aP(\000\000\r\002@\000\000h\024\000\000\006A \000\0014J\000\000\013$P\001iY\177r!}U\010BhaBc7\\`\000\000\000\000a9Z-`\000\000\000\0008\033np\000\000\000\000\000\000\000\000\000\000\000\000\000\000\007dgwVCgt\000`\000\000\000\000\000\000\000\000\001\177E8\001P\000\000\000\000\177p\000\000\000\000\000\000\000?|\000\000\000\000\000\000\000\037~$\037Z\000\022!}P\002-Kq\000\031\020~h\001{)t@\0216/D\001\027{; \n$\037Z\000XF\035\020\005vSi\0001#W\010\003\026ex@\032\032sD\001W{; \rq}Z\000r!}P\007+ m\000<#\016H\003na4@\037ZO$\002\001|L \020(ub\001\004\0206\020\010-Kq\000CQ#\010\004#.8@\"M\025D\002\027{; \021XlZ\001\017\017mP\011\005G-\000I\020~`\n\027f\006\0007\023H@\000TS|\000\011j}\010\003j4n@\030\r[\010\001\025LO\000\004\034A\002\000\177\024,0\005/=;\0001,\0338\000Hn\035\000\010$nH\001`\003\022 \002w(\022\000hdC@\007x;k\000\007\026\022H\002N>t\000\020#/T\000.]Q\000\010'&8\0008\011V@\002}|A\000\0162\0350\000s\003)@\007\037$p\001\004/b`\013odP\000\035G\177\000\004_\177^\000\0013\000x\003^/\010@\0215P(\000m\017[ \0033{\036\000\023ra\020\005]\036F\000\017lip\001?j\026@\016R=h\001Guy \017\013lz\000\003N>p\004)%\022\000:M?X\001?1\017@\021Uh \000V\001L\000\0047qv\0005j~\000\006>x \000&^C0\000;)q@\022\026\nx\001f\rB\000\006,f\n\000/E\024\000\003!\001\r\000?{\010\000\001\032s\023@\006\0200\030\000\025+2@\007\035#\022\00008O0\006\002\030k\037~$\037Z\000\000\000\000\017ND!4\000\000\000\000\007OB\0321\000\000\000\000\003[c\030Q0\000\000\000\001g`\033A`\000\000\000\000pz\022H\010\000\000\000\0006q`D(\000\000\000\000\032Z>1h\000\000\000\000\000\000\000\000\010\000\000\000\000`\000\000\000\010\000\000\000\000d\031@\000\000\000\000\000\000\006\014`\000\000\000\000\000\000\001\006\000\000\000\011\024r\030\000i7\031@\004r\005\034\0007\030-`\001@b2\031M\006S1\\p9 PH4\"\025\014\000\000\000\000\003\001Dd3\032\r&c9`ra1\030lF+\030\000\000\000\000\005\006sUXl\024@\000\000\000\024S0\000\001%r`\000\n/\026\000\000Rbp\000\005\027K\000\000)l\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\001U@\000\030~(\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\003,\000\0001|0\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\014\006Z\000\000cx \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000\032p\000\003\020\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000`5p\000\006 \002\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001@l\000\000\014@\024\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\001X@\000\031\000(\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\0032\000\0001~p\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\006f\000\000c} \000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\030\021,\000\001H\014@\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000#\020\000\003\020\037\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000`6@\000\006 :\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001@m \000\014@l\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000\000\000\020\000\000\000\000\025\000\000\000\000\004\000\000\000\005@\0000\0330\000\000\000\005 \000\000\000\001\000\000\000\001(\000\014\006r\000\000\000\001(\000\000\000\000 \000\000\000(\000\003\001^\000\000\000\000*\000\000\000\000\010\000\000\000\011@\000`7p\000\000\000\n@\000\000\000\002\000\000\000\002 \000\030\016\004\000\000\000\002P\000\000\000\000@\000\000\000D\000\006\003D\000\000\000\000T\000\000\000\000\020\000\000\000\020\000\001@q`\000\000\000\025\000\000\000\000\004\000\000\000\003`\0000\034P\000\000\000\005 \000\000\000\001\000\000\000\000p\000\014\007\030\000\000\000\001(\000\000\000\000 \000\000\000\032\000\003\001g\000\000\000\000*\000\000\000\000\010\000\000\000\006\000\000`:\000\000\000\000\n@\000\000\000\002\000\000\000\0010\000\030\016H\000\000\000\002P\000\000\000\000@\000\000\000(\000\006\003T\000\000\000\000P\000\000\000\000 \000\000\000,\000\001@u`\000\000\000\023\000\000\000\000\004\000\000\000\001 \0000\035P\000\000\000\004P\000\000\000\002\000\000\000\0018\000\014\007:\000\000\000\001\020\000\000\000\000 \000\000\000\014\000\003\001p\000\000\000\000\"\000\000\000\000\020\000\000\000\r@\000`<0\000\000\000\010@\000\000\000\004\000\000\000\003 \000\030\017\024\000\000\000\002\020\000\000\000\001\000\000\000\000d\000\006\003g\000\000\000\000D\000\000\000\000 \000\000\000\030\000\001@z@\000\000\000\020\000\000\000\000\010\000\000\000\010\000\0000\036p\000\000\000\004\000\000\000\000\002\000\000\000\001x\000\014\007b\000\000\000\000x\000\000\000\000@\000\000\000<\000\003\001z\000\000\000\000\036\000\000\000\000\020\000\000\000\016@\000`?\020\000\000\000\007@\000\000\000\004\000\000\000\003@\000\030\017|\000\000\000\001`\000\000\000\000@\000\000\000$\000\006\004\002\000\000\000\0008\000\000\000\000\020\000\000\000\010\000\001A\001@\000\000\000\016\000\000\000\000\004\000\000\000\001`\0000 P\000\000\000\003 \000\000\000\002\000\000\000\002(\000\014\010\032\000\000\000\000h\000\000\000\000@\000\000\000H\000\003\002\010@\000\000\000\032\000\000\000\000\020\000\000\000\021@\000`Bp\000\000\000\006@\000\000\000\004\000\000\000\004 \000\030\020h\000\000\000\001@\000\000\000\001\000\000\000\001\030\000\006\004\037\000\000\000\000,\000\000\000\000 \000\000\000!\000\001A\011\000\000\000\000\n\000\000\000\000\010\000\000\000\011`\0000\"H\000\000\000\002 \000\000\000\002\000\000\000\002P\000\014\010X\000\000\000\000H\000\000\000\000@\000\000\000R\000\003\002\026\000\000\000\000\020\000\000\000\000\020\000\000\000\024\000\000`F\000\000\000\000\003@\000\000\000\004\000\000\000\0050\000\030\021L\000\000\000\000@\000\000\000\000\000\000\000\000\020\000\006\0047\000\000\000\000\014\000\000\000\000\000\000\000\000\003\000\001A\016@\000\000\000\002\000\000\000\000\000\000\000\000\000@\0000#h\000\000\000\000 \000\000\000\000\000\000\000\000\010\000\014\011\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\003\002#@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001Aj \000\014Bb\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\003T\000\000\031\0058\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\007+\000\0002\np\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\016Z\000\000d\025\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\030\035<\000\001H) \000\000\000\000\000\000\000\000\000\000\000\000\000 \0000;\010\000\003\020Q\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000`v0\000\006!\037\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001Am \000\014B8\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\003[@\000\031\004d\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\0079\000\0002\0110\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\014\016t\000\000d\0250\000\003\021\000\000\000\000\000Aj\000\000\000\000\000\014(\000\000\000\000\001\007(\000\000\000\000\00000\000\000\000\000\004\035 \000\000\000\000\001L\000\000\000\000\000\002u\000\000\000\000\000\005x\000\000\000\000\001\003T\000\000\000\000\000\027(\000\000\000\000\004\016P\000\000\000\000\000[@\000\000\000\000\020:@\000\000\000\000\002g\000\000\000\000\000Kj\000\000\000\000\000\013\000\000\000\000\000\002/(\000\000\000\000\000+\020\000\000\000\000\010= \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000`}`\000\0063@\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001A{`\000\014g\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\003\003x\000\000\031M|\036\035-g#%hl2Y\007`\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \000\000\031\006D\000\001H4 \000\000\000\000\000\000a6\000\000\000\000\000\000\000\000\000\000\000\000\000\001\020\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001C1\000\000\000\010\021\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\006b@\000\000\020\034\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\rF\000\000\000 P\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\033\016\000\000\000@X\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\0306 \000\000\001\002p\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000\"X\000\000\002\001 \000\000\000\000\000\000\000\000\000\000\000\000\000@\000`6@\000\000\004\004\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001C2 \000\000\010\002\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\006e\000\000\000\030#\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\rK\000\000\0000:\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\033\030\000\000\000a$\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\03064\000\000\001A8\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000lx\000\000\003\005p\000\000\000\000\000\000\000\000\000\000\000\000\000@\000aZ\020\000\000\006\002`\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001C4`\000\000\014\010@\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\006j@\000\000\030\005\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\rV\000\000\000P\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\0330\000\000\001 \010\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\0306h\000\000\002@\010\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000m`\000\000\005\0000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000a[`\000\000\n\004@\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001C7`\000\000\024\010\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\006p\000\000\000(\n\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\rb\000\000\000P,\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\014\033H\000\000\n\007(\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000n(\000\000\014\013@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000a\\`\000\000\030:@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\003\006s@\000\000`\\\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\033\022\000\000\000\000\014\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\030\021,\000\000\000\000H\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000\033 \000\000\000\001p\000\000\000\000\000\000\000\000\000\000\000\000\000@\000aXp\000\000\000\005 \000\000\000\000\000\000\000\000\000\000\000\000\001\000\001C1 \000\000\000\r@\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\006b\000\000\000\000!\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\rF\000\000\000\000N\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\033\020\000\000\000\0014\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\0307 \000\000\004\000 \000\000\000\000\000\000\000\000\000\000\000\000\000 \0000nH\000\000\004\001@\000\000\000\000\000\000\000\000\000\000\000\000\000@\000a] \000\000\010\003@\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001C:`\000\000`\011@\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\006v@\000\001@3\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\ro\000\000\003\001&\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\033b\000\000\006\003L\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\0307L\000\000\014\011\030\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000o(\000\000\030\0260\000\000\000\000\000\000\000\000\000\000\000\000\000@\000a^p\000\00004`\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001C> \000\000`y@\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\006}@\000\001\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\r|\000\000\003\001F\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\033z\000\000\006\004\014\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\0307|\000\000\014\010\030\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000\032p\000\000\004\002`\000\000\000\000\000\000\000\000\000\000\000\000\000@\000a`\020\000\000\010\005`\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001C@@\000\000\020\014\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\007\001@\000\002!C\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\016\004\000\000\004CF\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\034\n\000\000\001\000d\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\0308\030\000\000\002\021P\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000p8\000\000\004\0030\000\000\000\000\000\000\000\000\000\000\000\000\000@\000aa\000\000\000\010\007\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001CB \000\0000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\007\005\000\000\000`\003\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\016\013\000\000\001@6\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\034\030\000\000\003\001l\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\03084\000\000\006\004\020\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000pp\000\000\014\0010\000\000\000\000\000\000\000\000\000\000\000\000\000@\000aap\000\000\030\n`\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001CD\000\000\0000%@\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\014\005\000\000\000`[\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\016\021\000\000\001AV\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\034$\000\000\003\003l\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\0308L\000\000\006\rX\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000q \000\000\014\0370\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001CE \000\000\023\002\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\007\013\000\000\000&\005\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\016\027\000\000\000L\014\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\0340\000\000\001\030\034\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\0308d\000\000\002 H\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000lH\000\000\000@ \000\000\000\000\000\000\000\000\000\000\000\000\000@\000`E0\000\000\001\002\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001@m\000\000\000\002\007\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\006c@\000\000\004\024\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\rE\000\000\000\0004\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\033\010\000\000\000\021\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\0306\030\000\000\000\"0\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000l@\000\000\000E@\000\000\000\000\000\000\000\000\000\000\000\000\000@\000ac \000\000\020\000@\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001C:\000\000\000 \002@\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\007\r@\000\000\0000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\016\034\000\000\001\000\014\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\034:\000\000\002\000\034\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\0308x\000\000\020\004 \000\000\000\000\000\000\000\000\000\000\000\000\000 \0000qx\000\000 \n@\000\000\000\000\000\000\000\000\000\000\000\000\000@\000ad\000\000\0008\030@\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001CH \000\000pA\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\007\021\000\000\000 \035\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\016#\000\000\000@<\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\034H\000\000\001\000|\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\0309\024\000\000\002\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000r0\000\000\014\0010\000\000\000\000\000\000\000\000\000\000\000\000\000@\000adp\000\000\030\006`\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001CJ\000\000\0000\025@\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\007\024@\000\000`;\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\016*\000\000\001A\026\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\034V\000\000\003\002l\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\03090\000\000\006\006X\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000rh\000\000\014\0170\000\000\000\000\000\000\000\000\000\000\000\000\000@\000ae`\000\000\030\"`\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001CK`\000\0000M@\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\007\030\000\000\000a+\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\0161\000\000\001Bv\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\034d\000\000\003\007,\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\0309L\000\000\006\017X\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000s \000\000\014\010 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001CM \000\0000e@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\003\007\033\000\000\000a[\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\034n\000\000\011\000\034\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\0309d\000\000\022\0018\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000sX\000\000$\004p\000\000\000\000\000\000\000\000\000\000\000\000\000@\000agP\000\000H\r`\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001CO`\000\001\020#@\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\007 @\000\002 W\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\016C\000\000\004AN\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\035\n\000\000\011\003\\\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\030:\034\000\000\022\0108\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000tH\000\000$\022p\000\000\000\000\000\000\000\000\000\000\000\000\000@\000ai0\000\000H)`\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001CS \000\001\020[@\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\007'@\000\002!G\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\016Q\000\000\004C.\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\035&\000\000\011\007\034\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\030:T\000\000\022\0178\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000u8\000\000\024\001p\000\000\000\000\000\000\000\000\000\000\000\000\000@\000ak\020\000\000(\007`\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001CV`\000\000P\027@\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\007.@\000\001 ?\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\016_\000\000\002A\036\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\035B\000\000\005\002|\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\030;\014\000\000\n\006x\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000v(\000\000\024\017p\000\000\000\000\000\000\000\000\000\000\000\000\000@\000alp\000\000(#`\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001CZ \000\000PO@\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\0075@\000\001!/\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\016m\000\000\002B~\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\035^\000\000\005\006<\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\030;D\000\000\n\rx\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000w\030\000\000\024\035p\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000anP\000\000(?`\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\006d@\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\004+\000\000\000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\006h\000\000\000\0004\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\0306\034\000\000\000\001\030\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000l(\000\000\000\003\020\000\000\000\000\000\000\000\000\000\000\000\000\000@\000aX@\000\000\000\007`\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001C1@\000\000\000\022@\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\006d\000\000\000\000+\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\016\032\000\000\001\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\0342\000\000\001\000$\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\030;\\\000\000\002\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000w@\000\000\004\002 \000\000\000\000\000\000\000\000\000\000\000\000\000@\000ao\020\000\000 \000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001C^@\000\0000-\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\007=@\000\000`z\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\016|\000\000\001C4\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\035z\000\000\003\007h\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\030;x\000\000\002\001\030\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000wx\000\000\004\002@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000ap\000\000\000\010\005 \000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\007<@\000\001\000\022\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\017\001\000\000\000@\\\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\014\036\004\000\000\001\001<\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0000x\030\000\000\004\004\020\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001Ca\000\000\000\000\030@\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\007B@\000\000\0002\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\017\006\000\000\000\000f\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\036\016\000\000\000\001P\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\030< \000\000\000\003(\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000xH\000\000\000\006`\000\000\000\000\000\000\000\000\000\000\000\000\000@\000aq \000\000\000\r`\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001Cb`\000\000\000\034\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\007F\000\000\000 *\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\017\r\000\000\000@V\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\036\034\000\000\000\001d\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\030<<\000\000\002\002`\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000y\000\000\000\004\005P\000\000\000\000\000\000\000\000\000\000\000\000\000@\000ar\020\000\000\010\010@\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001@k@\000\000\020\021\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\007I\000\000\000 #\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\017\023\000\000\000@H\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\033H\000\000\001\001\024\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\030@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\030`\014\000\000w@\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \0001@ \000\001y@\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000c\000`\000\003r\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001?, \000\006|\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\014\004\000\000\rx\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\025\017\000\000\036\020\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\0141f\000\000= \000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\030`$\000\000z@\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \0001@X\000\001n@\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000c\001@\000\003]\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001F\003 \000\007:\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\003w@\000\016p\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\007n\000\000\035X\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\014\017`\000\000; \000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\030`<\000\000z \000\000\000\000\000\000\000\000\000\000\000\000\000\000 \0001A\010\000\001k@\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000c\002 \000\003W\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001F\005\000\000\007,\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\014\n@\000\016X\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\030\027\000\000\036@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\01402\000\000
\020\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\030a,\000\000y\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \0001B`\000\001r\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000be@\000\003R\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001EK \000\007\"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\013\027@\000\016@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\030.\000\000\034`\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\0140^\000\00090\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\030 \000\000\000r@\000\000\000\000\000\000\000\000\000\000\000\000\000\000 \0001C\000\000\001d@\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000`2P\000\003H\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001@e`\000\007\020\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\014\031\000\000\016\034\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\0304\000\000\036\030\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010\000\0140l\000\0008`\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\030a`\000\000q \000\000\000\000\000\000\000\000\000\000\000\000\000\000 \0000BH\000\001b\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000@\000c\007 \000\003C\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\001F\017\000\000\007\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000\003\014 \000\000\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\006\030D\000\000\033x\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0141\n\000\0007p\000\000\000\000\000\000\000\000\000\000\000\000\000\n\000\000\000\000\000\000\000\000\000\010\000\0141\034\000\000c\n\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000(\000\000\000\000\000\000\014a\016\000\000f\014\020\000\0060{\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\030k8\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000Laj^4$4s\033;n`\000\n\000\005@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000f\022`\000\0061\026\000\0003\011@\000\003\030L\000\000\031Dh\000\001L&@\000\014b8\000\000f\023@\000\0061\036\000\0003\011p\000\003\030P\000\000\031E\000\000\001L(@\000\014bD\000\000f\024@\000\0061$\000\0003\n0\000\003\030S\000\000\031E \000\001L*\000\000\014bT\000\000f\025 \000\0061,\000\0003\n`\000\003\030W\000\000\031E8\000\001L,\000\000\014b`\000\000f\026 \000\00612\000\0003\013 \000\003\030Z\000\000\031EX\000\001L-@\000\014bp\000\000f\027\000\000\0061:\000\0003\013P\000\003\030^\000\000\031Ep\000\001L/@\000\014b|\000\000f\030\000\000\0061@\000\0003\014\020\000\003\030a\000\000\031F\020\000\001L1\000\000\014c\014\000\000f\030`\000\0061H\000\0003\014@\000\003\030e\000\000\031F(\000\001L3\000\000\014c\030\000\000f\031`\000\0061N\000\0003\r\000\000\003\030h\000\000\031FH\000\001L4@\000\014c(\000\000f\032@\000\0061V\000\0003\r0\000\003\030l\000\000\031F`\000\001L6@\000\014c4\000\000f\033@\000\0061\\\000\0003\rp\000\003\030o\000\000\031G\000\000\001L8\000\000\014cD\000\000f\034 \000\0061d\000\0003\016 \000\003\030s\000\000\031G\030\000\001L:\000\000\014cP\000\000f\035 \000\0061j\000\0003\016`\000\003\030v\000\000\031G8\000\001L;@\000\014c`\000\000f\036\000\000\0061r\000\0003\017\020\000\003\030z\000\000\031GP\000\001L=@\000\014cl\000\000f\037\000\000\0061x\000\0003\017P\000\003\030}\000\000\031Gp\000\001L?\000\000\014c|\000\000f\037`\000\0062\000\000\0003\020\000\000\003\031\001\000\000\031H\010\000\001LA\000\000\014d\010\000\000f `\000\0062\006\000\0003\020@\000\003\031\004\000\000\031H(\000\001LB@\000\014d\030\000\000f!@\000\0062\016\000\0003\020p\000\003\031\010\000\000\031H@\000\001LD@\000\014d$\000\000f\"@\000\0062\024\000\0003\0210\000\003\031\013\000\000\031H`\000\001LF\000\000\014d4\000\000f# \000\0062\034\000\0003\021`\000\003\031\017\000\000\031Hx\000\001LH\000\000\014d@\000\000f$ \000\0062\"\000\0003\022 \000\003\031\022\000\000\031I\030\000\001LI@\000\014dP\000\000f%\000\000\0062*\000\0003\022P\000\003\031\026\000\000\031I0\000\001LK@\000\014d\\\000\000f&\000\000\00620\000\0003\023\020\000\003\031\031\000\000\031IP\000\001LM\000\000\014dl\000\000f&`\000\00628\000\0003\023@\000\003\031\035\000\000\031Ih\000\001LO\000\000\014dx\000\000f'`\000\0062>\000\0003\024\000\000\003\031 \000\000\031J\010\000\001LP@\000\014e\010\000\000f(@\000\0062F\000\0003\0240\000\003\031$\000\000\031J \000\001LR@\000\014e\024\000\000f)@\000\0062L\000\0003\024p\000\003\031'\000\000\031J@\000\001LT\000\000\014e$\000\000f* \000\0062T\000\0003\025 \000\003\031+\000\000\031JX\000\001LV\000\000\014e0\000\000f+ \000\0062Z\000\0003\025`\000\003\031.\000\000\031Jx\000\001LW@\000\014e@\000\000f,\000\000\0062b\000\0003\026\020\000\003\0312\000\000\031K\020\000\001LY@\000\014eL\000\000f-\000\000\0062h\000\0003\026P\000\003\0315\000\000\031K0\000\001L[\000\000\014e\\\000\000f-`\000\0062p\000\0003\027\000\000\003\0319\000\000\031KH\000\001L]\000\000\014eh\000\000f.`\000\0062v\000\0003\027@\000\003\031<\000\000\031Kh\000\001L^@\000\014ex\000\000f/@\000\0062~\000\0003\027p\000\003\031@\000\000\031L\000\000\001L`@\000\014f\004\000\000f0@\000\0063\004\000\0003\0300\000\003\031C\000\000\031L \000\001Lb\000\000\014f\024\000\000f1 \000\0063\014\000\0003\030`\000\003\031G\000\000\031L8\000\001Ld\000\000\014f \000\000f2 \000\0063\022\000\0003\031 \000\003\031J\004\nM\006I$@\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001BX \000\013p\014\000\000_\000`\000\005x\006\000\000/@0\000\002|\003\000\000\027`\030\000\001>\001@\000\013p\014\000\000_\000a~\177?_ow{}~\177?_ow{|\000\000",0xac6);
+ private static final int[] _data5 = decodeData("\000\000\000\004\000\000\000\000 \035l \000\001n\000\000\000\000\000\000\000\020\000\000\000\001\004\000\000\000\000\000\000\000\000\005\177`\000\000\000\000\000\000\000\177p\000\000\000\000\000\000\000@\022\000\000\000\000\000\000\000\000\000:\000\000\000\003T\000\000\000\035\020\000\000\001g\000\000\0003CP\000\003\020j\007\023\010\000\000\000\000\000\000'\177\177\177\177\177\177\177\177|\000\006/\004\000\000\000\000\000?|H?5\"\020Z\030_~$\037ZQ\010-\014\037F~!r\020\000:g\007\177\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\001\177p\000\000\000\000\000\000\002\177p\000\000\000\000\000\000\000?H+'.\031\0134\021\037j/4Y\021l\ruOv\020k\032AP\036T'{:\027\033E&\010\rc~\011\022$I\000\020?y\177*U*U*U(6\177\"Z\021\005FS0^?VwEU\026{{\032\037lv\017\025=i\0326OwG\016\033|#\013\034'|Lf3\031L:xC\177@\000\000\000\000\000\000\001\177`\000\000\000\000\000\000\000\177p\000\000\000\000\000\000\001\177x\000\000\000\000\000\000\000#{\177\177\177\000\000\000\000\017|\000\000\000\000\000\000\000\030~\177\177\177`\000\000\000\007\177@\000\000\000\000\000\000\002\000\022!}U\010Bh`\177y\020~jD!40?\001\017<\020own\011\037R=~\003T\0032D\017tH\021\"jhGNg|N\005*\016D\021\nS~S,\022\001zmwi\177\nU*U*U*T\1773\\16\022tJ\004?s\001MA\\4\002Y \000\005.,q3\nd\020\0003Q\0349\n\026Rg\177\000\000\000\000\000\000\000\003dFL&\031E\013@9\177@\000\000\000\000\000\000\000\177y\020~jD!40\017K./\032\024+N:gl8wFWX\177OSy(\003 \014p,\035)~\002\021\010D\"\017E\030\177E*U*U*U\022?p\000\000\000\000\000\000\000\037|\000\000\000\000\000\000\000/~\000\000\000\000\000\000\000\007~I\007vT\"\013#\003d\006L&\031E\013@={fuevl\005\033L~\024?\"\024\003>>9) {
- case 0x80: run_10000(); break;
- case 0x81: run_10200(); break;
- case 0x82: run_10400(); break;
- case 0x83: run_10600(); break;
- case 0x84: run_10800(); break;
- case 0x85: run_10a00(); break;
- case 0x86: run_10c00(); break;
- case 0x87: run_10e00(); break;
- case 0x88: run_11000(); break;
- case 0x89: run_11200(); break;
- case 0x8a: run_11400(); break;
- case 0x8b: run_11600(); break;
- case 0x8c: run_11800(); break;
- case 0x8d: run_11a00(); break;
- case 0x8e: run_11c00(); break;
- case 0x8f: run_11e00(); break;
- case 0x90: run_12000(); break;
- case 0x91: run_12200(); break;
- case 0x92: run_12400(); break;
- case 0x93: run_12600(); break;
- case 0x94: run_12800(); break;
- case 0x95: run_12a00(); break;
- case 0x96: run_12c00(); break;
- case 0x97: run_12e00(); break;
- case 0x98: run_13000(); break;
- case 0x99: run_13200(); break;
- case 0x9a: run_13400(); break;
- case 0x9b: run_13600(); break;
- case 0x9c: run_13800(); break;
- case 0x9d: run_13a00(); break;
- case 0x9e: run_13c00(); break;
- case 0x9f: run_13e00(); break;
- case 0xa0: run_14000(); break;
- case 0xa1: run_14200(); break;
- case 0xa2: run_14400(); break;
- case 0xa3: run_14600(); break;
- case 0xa4: run_14800(); break;
- case 0xa5: run_14a00(); break;
- case 0xa6: run_14c00(); break;
- case 0xa7: run_14e00(); break;
- case 0xa8: run_15000(); break;
- case 0xa9: run_15200(); break;
- case 0xaa: run_15400(); break;
- case 0xab: run_15600(); break;
- case 0xac: run_15800(); break;
- case 0xad: run_15a00(); break;
- case 0xae: run_15c00(); break;
- case 0xaf: run_15e00(); break;
- case 0xb0: run_16000(); break;
- case 0xb1: run_16200(); break;
- case 0xb2: run_16400(); break;
- case 0xb3: run_16600(); break;
- case 0xb4: run_16800(); break;
- case 0xb5: run_16a00(); break;
- case 0xb6: run_16c00(); break;
- case 0xb7: run_16e00(); break;
- case 0xb8: run_17000(); break;
- case 0xb9: run_17200(); break;
- case 0xba: run_17400(); break;
- case 0xbb: run_17600(); break;
- case 0xbc: run_17800(); break;
- case 0xbd: run_17a00(); break;
- case 0xbe: run_17c00(); break;
- case 0xbf: run_17e00(); break;
- case 0xc0: run_18000(); break;
- case 0xc1: run_18200(); break;
- case 0xc2: run_18400(); break;
- case 0xc3: run_18600(); break;
- case 0xc4: run_18800(); break;
- case 0xc5: run_18a00(); break;
- case 0xc6: run_18c00(); break;
- case 0xc7: run_18e00(); break;
- case 0xc8: run_19000(); break;
- case 0xc9: run_19200(); break;
- case 0xca: run_19400(); break;
- case 0xcb: run_19600(); break;
- case 0xcc: run_19800(); break;
- case 0xcd: run_19a00(); break;
- case 0xce: run_19c00(); break;
- case 0xcf: run_19e00(); break;
- case 0xd0: run_1a000(); break;
- case 0xd1: run_1a200(); break;
- case 0xd2: run_1a400(); break;
- case 0xd3: run_1a600(); break;
- case 0xd4: run_1a800(); break;
- case 0xd5: run_1aa00(); break;
- case 0xd6: run_1ac00(); break;
- case 0xd7: run_1ae00(); break;
- case 0xd8: run_1b000(); break;
- case 0xd9: run_1b200(); break;
- case 0xda: run_1b400(); break;
- case 0xdb: run_1b600(); break;
- case 0xdc: run_1b800(); break;
- case 0xdd: run_1ba00(); break;
- case 0xde: run_1bc00(); break;
- case 0xdf: run_1be00(); break;
- case 0xe0: run_1c000(); break;
- case 0xe1: run_1c200(); break;
- case 0xe2: run_1c400(); break;
- case 0xe3: run_1c600(); break;
- case 0xe4: run_1c800(); break;
- case 0xe5: run_1ca00(); break;
- case 0xe6: run_1cc00(); break;
- case 0xe7: run_1ce00(); break;
- case 0xe8: run_1d000(); break;
- case 0xe9: run_1d200(); break;
- case 0xea: run_1d400(); break;
- case 0xeb: run_1d600(); break;
- case 0xec: run_1d800(); break;
- case 0xed: run_1da00(); break;
- case 0xee: run_1dc00(); break;
- case 0xef: run_1de00(); break;
- case 0xf0: run_1e000(); break;
- case 0xf1: run_1e200(); break;
- case 0xf2: run_1e400(); break;
- case 0xf3: run_1e600(); break;
- case 0xf4: run_1e800(); break;
- case 0xf5: run_1ea00(); break;
- case 0xf6: run_1ec00(); break;
- case 0xf7: run_1ee00(); break;
- case 0xf8: run_1f000(); break;
- case 0xf9: run_1f200(); break;
- case 0xfa: run_1f400(); break;
- case 0xfb: run_1f600(); break;
- case 0xfc: run_1f800(); break;
- case 0xfd: run_1fa00(); break;
- case 0xfe: run_1fc00(); break;
- case 0xff: run_1fe00(); break;
- case 0x100: run_20000(); break;
- case 0x101: run_20200(); break;
- case 0x102: run_20400(); break;
- case 0x103: run_20600(); break;
- case 0x104: run_20800(); break;
- case 0x105: run_20a00(); break;
- case 0x106: run_20c00(); break;
- case 0x107: run_20e00(); break;
- case 0x108: run_21000(); break;
- case 0x109: run_21200(); break;
- case 0x10a: run_21400(); break;
- case 0x10b: run_21600(); break;
- case 0x10c: run_21800(); break;
- case 0x10d: run_21a00(); break;
- case 0x10e: run_21c00(); break;
- case 0x10f: run_21e00(); break;
- case 0x110: run_22000(); break;
- case 0x111: run_22200(); break;
- case 0x112: run_22400(); break;
- case 0x113: run_22600(); break;
- case 0x114: run_22800(); break;
- case 0x115: run_22a00(); break;
- case 0x116: run_22c00(); break;
- case 0x117: run_22e00(); break;
- case 0x118: run_23000(); break;
- case 0x119: run_23200(); break;
- case 0x11a: run_23400(); break;
- case 0x11b: run_23600(); break;
- case 0x11c: run_23800(); break;
- case 0x11d: run_23a00(); break;
- case 0x11e: run_23c00(); break;
- case 0x11f: run_23e00(); break;
- case 0x120: run_24000(); break;
- case 0x121: run_24200(); break;
- case 0x122: run_24400(); break;
- case 0x123: run_24600(); break;
- case 0x124: run_24800(); break;
- case 0x125: run_24a00(); break;
- case 0x126: run_24c00(); break;
- case 0x127: run_24e00(); break;
- case 0x128: run_25000(); break;
- case 0x129: run_25200(); break;
- case 0x12a: run_25400(); break;
- case 0x12b: run_25600(); break;
- case 0x12c: run_25800(); break;
- case 0x12d: run_25a00(); break;
- case 0x12e: run_25c00(); break;
- case 0x12f: run_25e00(); break;
- case 0x130: run_26000(); break;
- case 0x131: run_26200(); break;
- case 0x132: run_26400(); break;
- case 0x133: run_26600(); break;
- case 0x134: run_26800(); break;
- case 0x135: run_26a00(); break;
- case 0x136: run_26c00(); break;
- case 0x137: run_26e00(); break;
- case 0x138: run_27000(); break;
- case 0x139: run_27200(); break;
- case 0x13a: run_27400(); break;
- case 0x13b: run_27600(); break;
- case 0x13c: run_27800(); break;
- case 0x13d: run_27a00(); break;
- case 0x13e: run_27c00(); break;
- case 0x13f: run_27e00(); break;
- case 0x140: run_28000(); break;
- case 0x141: run_28200(); break;
- case 0x142: run_28400(); break;
- case 0x143: run_28600(); break;
- case 0x144: run_28800(); break;
- case 0x145: run_28a00(); break;
- case 0x146: run_28c00(); break;
- case 0x147: run_28e00(); break;
- case 0x148: run_29000(); break;
- case 0x149: run_29200(); break;
- case 0x14a: run_29400(); break;
- case 0x14b: run_29600(); break;
- case 0x14c: run_29800(); break;
- case 0x14d: run_29a00(); break;
- case 0x14e: run_29c00(); break;
- case 0x14f: run_29e00(); break;
- case 0x150: run_2a000(); break;
- case 0x151: run_2a200(); break;
- case 0x152: run_2a400(); break;
- case 0x153: run_2a600(); break;
- case 0x154: run_2a800(); break;
- case 0x155: run_2aa00(); break;
- case 0x156: run_2ac00(); break;
- case 0x157: run_2ae00(); break;
- case 0x158: run_2b000(); break;
- case 0x159: run_2b200(); break;
- case 0x15a: run_2b400(); break;
- case 0x15b: run_2b600(); break;
- case 0x15c: run_2b800(); break;
- case 0x15d: run_2ba00(); break;
- case 0x15e: run_2bc00(); break;
- case 0x15f: run_2be00(); break;
- case 0x160: run_2c000(); break;
- case 0x161: run_2c200(); break;
- case 0x162: run_2c400(); break;
- case 0x163: run_2c600(); break;
- case 0x164: run_2c800(); break;
- case 0x165: run_2ca00(); break;
- case 0x166: run_2cc00(); break;
- case 0x167: run_2ce00(); break;
- case 0x168: run_2d000(); break;
- case 0x169: run_2d200(); break;
- case 0x16a: run_2d400(); break;
- case 0x16b: run_2d600(); break;
- case 0x16c: run_2d800(); break;
- case 0x16d: run_2da00(); break;
- case 0x16e: run_2dc00(); break;
- case 0x16f: run_2de00(); break;
- case 0x170: run_2e000(); break;
- case 0x171: run_2e200(); break;
- case 0x172: run_2e400(); break;
- case 0x173: run_2e600(); break;
- case 0x174: run_2e800(); break;
- case 0x175: run_2ea00(); break;
- case 0x176: run_2ec00(); break;
- case 0x177: run_2ee00(); break;
- case 0x178: run_2f000(); break;
- case 0x179: run_2f200(); break;
- case 0x17a: run_2f400(); break;
- case 0x17b: run_2f600(); break;
- case 0x17c: run_2f800(); break;
- case 0x17d: run_2fa00(); break;
- case 0x17e: run_2fc00(); break;
- case 0x17f: run_2fe00(); break;
- case 0x180: run_30000(); break;
- case 0x181: run_30200(); break;
- case 0x182: run_30400(); break;
- case 0x183: run_30600(); break;
- case 0x184: run_30800(); break;
- case 0x185: run_30a00(); break;
- case 0x186: run_30c00(); break;
- case 0x187: run_30e00(); break;
- case 0x188: run_31000(); break;
- case 0x189: run_31200(); break;
- case 0x18a: run_31400(); break;
- case 0x18b: run_31600(); break;
- case 0x18c: run_31800(); break;
- case 0x18d: run_31a00(); break;
- case 0x18e: run_31c00(); break;
- case 0x18f: run_31e00(); break;
- case 0x190: run_32000(); break;
- case 0x191: run_32200(); break;
- case 0x192: run_32400(); break;
- case 0x193: run_32600(); break;
- case 0x194: run_32800(); break;
- case 0x195: run_32a00(); break;
- case 0x196: run_32c00(); break;
- case 0x197: run_32e00(); break;
- case 0x198: run_33000(); break;
- case 0x199: run_33200(); break;
- case 0x19a: run_33400(); break;
- case 0x19b: run_33600(); break;
- case 0x19c: run_33800(); break;
- case 0x19d: run_33a00(); break;
- case 0x19e: run_33c00(); break;
- case 0x19f: run_33e00(); break;
- case 0x1a0: run_34000(); break;
- case 0x1a1: run_34200(); break;
- case 0x1a2: run_34400(); break;
- case 0x1a3: run_34600(); break;
- case 0x1a4: run_34800(); break;
- case 0x1a5: run_34a00(); break;
- case 0x1a6: run_34c00(); break;
- case 0x1a7: run_34e00(); break;
- case 0x1a8: run_35000(); break;
- case 0x1a9: run_35200(); break;
- case 0x1aa: run_35400(); break;
- case 0x1ab: run_35600(); break;
- case 0x1ac: run_35800(); break;
- case 0x1ad: run_35a00(); break;
- case 0x1ae: run_35c00(); break;
- case 0x1af: run_35e00(); break;
- case 0x1b0: run_36000(); break;
- case 0x1b1: run_36200(); break;
- case 0x1b2: run_36400(); break;
- case 0x1b3: run_36600(); break;
- case 0x1b4: run_36800(); break;
- case 0x1b5: run_36a00(); break;
- case 0x1b6: run_36c00(); break;
- case 0x1b7: run_36e00(); break;
- case 0x1b8: run_37000(); break;
- case 0x1b9: run_37200(); break;
- case 0x1ba: run_37400(); break;
- case 0x1bb: run_37600(); break;
- case 0x1bc: run_37800(); break;
- case 0x1bd: run_37a00(); break;
- case 0x1be: run_37c00(); break;
- case 0x1bf: run_37e00(); break;
- case 0x1c0: run_38000(); break;
- case 0x1c1: run_38200(); break;
- case 0x1c2: run_38400(); break;
- case 0x1c3: run_38600(); break;
- case 0x1c4: run_38800(); break;
- case 0x1c5: run_38a00(); break;
- case 0x1c6: run_38c00(); break;
- case 0x1c7: run_38e00(); break;
- case 0x1c8: run_39000(); break;
- case 0x1c9: run_39200(); break;
- case 0x1ca: run_39400(); break;
- case 0x1cb: run_39600(); break;
- case 0x1cc: run_39800(); break;
- case 0x1cd: run_39a00(); break;
- case 0x1ce: run_39c00(); break;
- case 0x1cf: run_39e00(); break;
- case 0x1d0: run_3a000(); break;
- case 0x1d1: run_3a200(); break;
- case 0x1d2: run_3a400(); break;
- case 0x1d3: run_3a600(); break;
- case 0x1d4: run_3a800(); break;
- case 0x1d5: run_3aa00(); break;
- case 0x1d6: run_3ac00(); break;
- case 0x1d7: run_3ae00(); break;
- case 0x1d8: run_3b000(); break;
- case 0x1d9: run_3b200(); break;
- case 0x1da: run_3b400(); break;
- case 0x1db: run_3b600(); break;
- case 0x1dc: run_3b800(); break;
- case 0x1dd: run_3ba00(); break;
- case 0x1de: run_3bc00(); break;
- case 0x1df: run_3be00(); break;
- case 0x1e0: run_3c000(); break;
- case 0x1e1: run_3c200(); break;
- case 0x1e2: run_3c400(); break;
- case 0x1e3: run_3c600(); break;
- case 0x1e4: run_3c800(); break;
- case 0x1e5: run_3ca00(); break;
- case 0x1e6: run_3cc00(); break;
- case 0x1e7: run_3ce00(); break;
- case 0x1e8: run_3d000(); break;
- case 0x1e9: run_3d200(); break;
- case 0x1ea: run_3d400(); break;
- case 0x1eb: run_3d600(); break;
- case 0x1ec: run_3d800(); break;
- case 0x1ed: run_3da00(); break;
- case 0x1ee: run_3dc00(); break;
- case 0x1ef: run_3de00(); break;
- case 0x1f0: run_3e000(); break;
- case 0x1f1: run_3e200(); break;
- case 0x1f2: run_3e400(); break;
- case 0x1f3: run_3e600(); break;
- case 0x1f4: run_3e800(); break;
- case 0x1f5: run_3ea00(); break;
- case 0x1f6: run_3ec00(); break;
- case 0x1f7: run_3ee00(); break;
- case 0x1f8: run_3f000(); break;
- case 0x1f9: run_3f200(); break;
- case 0x1fa: run_3f400(); break;
- case 0x1fb: run_3f600(); break;
- case 0x1fc: run_3f800(); break;
- case 0x1fd: run_3fa00(); break;
- case 0x1fe: run_3fc00(); break;
- case 0x1ff: run_3fe00(); break;
- case 0x200: run_40000(); break;
- case 0x201: run_40200(); break;
- case 0x202: run_40400(); break;
- case 0x203: run_40600(); break;
- case 0x204: run_40800(); break;
- case 0x205: run_40a00(); break;
- case 0x206: run_40c00(); break;
- case 0x207: run_40e00(); break;
- case 0x208: run_41000(); break;
- case 0x209: run_41200(); break;
- case 0x20a: run_41400(); break;
- case 0x20b: run_41600(); break;
- case 0x20c: run_41800(); break;
- case 0x20d: run_41a00(); break;
- case 0x20e: run_41c00(); break;
- case 0x20f: run_41e00(); break;
- case 0x210: run_42000(); break;
- case 0x211: run_42200(); break;
- case 0x212: run_42400(); break;
- case 0x213: run_42600(); break;
- case 0x214: run_42800(); break;
- case 0x215: run_42a00(); break;
- case 0x216: run_42c00(); break;
- case 0x217: run_42e00(); break;
- case 0x218: run_43000(); break;
- case 0x219: run_43200(); break;
- case 0x21a: run_43400(); break;
- case 0x21b: run_43600(); break;
- case 0x21c: run_43800(); break;
- case 0x21d: run_43a00(); break;
- case 0x21e: run_43c00(); break;
- case 0x21f: run_43e00(); break;
- case 0x220: run_44000(); break;
- case 0x221: run_44200(); break;
- case 0x222: run_44400(); break;
- case 0x223: run_44600(); break;
- case 0x224: run_44800(); break;
- case 0x225: run_44a00(); break;
- case 0x226: run_44c00(); break;
- case 0x227: run_44e00(); break;
- case 0x228: run_45000(); break;
- case 0x229: run_45200(); break;
- case 0x22a: run_45400(); break;
- case 0x22b: run_45600(); break;
- case 0x22c: run_45800(); break;
- case 0x22d: run_45a00(); break;
- case 0x22e: run_45c00(); break;
- case 0x22f: run_45e00(); break;
- case 0x230: run_46000(); break;
- case 0x231: run_46200(); break;
- case 0x232: run_46400(); break;
- case 0x233: run_46600(); break;
- case 0x234: run_46800(); break;
- case 0x235: run_46a00(); break;
- case 0x236: run_46c00(); break;
- case 0x237: run_46e00(); break;
- case 0x238: run_47000(); break;
- case 0x239: run_47200(); break;
- case 0x23a: run_47400(); break;
- case 0x23b: run_47600(); break;
- case 0x23c: run_47800(); break;
- case 0x23d: run_47a00(); break;
- case 0x23e: run_47c00(); break;
- case 0x23f: run_47e00(); break;
- case 0x240: run_48000(); break;
- case 0x241: run_48200(); break;
- case 0x242: run_48400(); break;
- case 0x243: run_48600(); break;
- case 0x244: run_48800(); break;
- case 0x245: run_48a00(); break;
- case 0x246: run_48c00(); break;
- case 0x247: run_48e00(); break;
- case 0x248: run_49000(); break;
- case 0x249: run_49200(); break;
- case 0x24a: run_49400(); break;
- case 0x24b: run_49600(); break;
- case 0x24c: run_49800(); break;
- case 0x24d: run_49a00(); break;
- case 0x24e: run_49c00(); break;
- case 0x24f: run_49e00(); break;
- case 0x250: run_4a000(); break;
- case 0x251: run_4a200(); break;
- case 0x252: run_4a400(); break;
- case 0x253: run_4a600(); break;
- case 0x254: run_4a800(); break;
- case 0x255: run_4aa00(); break;
- case 0x256: run_4ac00(); break;
- case 0x257: run_4ae00(); break;
- case 0x258: run_4b000(); break;
- case 0x259: run_4b200(); break;
- case 0x25a: run_4b400(); break;
- case 0x25b: run_4b600(); break;
- case 0x25c: run_4b800(); break;
- case 0x25d: run_4ba00(); break;
- case 0x25e: run_4bc00(); break;
- case 0x25f: run_4be00(); break;
- case 0x260: run_4c000(); break;
- case 0x261: run_4c200(); break;
- case 0x262: run_4c400(); break;
- case 0x263: run_4c600(); break;
- case 0x264: run_4c800(); break;
- case 0x265: run_4ca00(); break;
- case 0x266: run_4cc00(); break;
- case 0x267: run_4ce00(); break;
- case 0x268: run_4d000(); break;
- case 0x269: run_4d200(); break;
- case 0x26a: run_4d400(); break;
- case 0x26b: run_4d600(); break;
- case 0x26c: run_4d800(); break;
- case 0x26d: run_4da00(); break;
- case 0x26e: run_4dc00(); break;
- case 0x26f: run_4de00(); break;
- case 0x270: run_4e000(); break;
- case 0x271: run_4e200(); break;
- case 0x272: run_4e400(); break;
- case 0x273: run_4e600(); break;
- case 0x274: run_4e800(); break;
- case 0x275: run_4ea00(); break;
- case 0x276: run_4ec00(); break;
- case 0x277: run_4ee00(); break;
- case 0x278: run_4f000(); break;
- case 0x279: run_4f200(); break;
- case 0x27a: run_4f400(); break;
- case 0x27b: run_4f600(); break;
- case 0x27c: run_4f800(); break;
- case 0x27d: run_4fa00(); break;
- case 0x27e: run_4fc00(); break;
- case 0x27f: run_4fe00(); break;
- case 0x280: run_50000(); break;
- case 0x281: run_50200(); break;
- case 0x282: run_50400(); break;
- case 0x283: run_50600(); break;
- case 0x284: run_50800(); break;
- case 0x285: run_50a00(); break;
- case 0x286: run_50c00(); break;
- case 0x287: run_50e00(); break;
- case 0x288: run_51000(); break;
- case 0x289: run_51200(); break;
- case 0x28a: run_51400(); break;
- case 0x28b: run_51600(); break;
- case 0x28c: run_51800(); break;
- case 0x28d: run_51a00(); break;
- case 0x28e: run_51c00(); break;
- case 0x28f: run_51e00(); break;
- case 0x290: run_52000(); break;
- case 0x291: run_52200(); break;
- case 0x292: run_52400(); break;
- case 0x293: run_52600(); break;
- case 0x294: run_52800(); break;
- case 0x295: run_52a00(); break;
- case 0x296: run_52c00(); break;
- case 0x297: run_52e00(); break;
- case 0x298: run_53000(); break;
- case 0x299: run_53200(); break;
- case 0x29a: run_53400(); break;
- case 0x29b: run_53600(); break;
- case 0x29c: run_53800(); break;
- case 0x29d: run_53a00(); break;
- case 0x29e: run_53c00(); break;
- case 0x29f: run_53e00(); break;
- case 0x2a0: run_54000(); break;
- case 0x2a1: run_54200(); break;
- case 0x2a2: run_54400(); break;
- case 0x2a3: run_54600(); break;
- case 0x2a4: run_54800(); break;
- case 0x2a5: run_54a00(); break;
- case 0x2a6: run_54c00(); break;
- case 0x2a7: run_54e00(); break;
- case 0x2a8: run_55000(); break;
- case 0x2a9: run_55200(); break;
- case 0x2aa: run_55400(); break;
- case 0x2ab: run_55600(); break;
- case 0x2ac: run_55800(); break;
- case 0x2ad: run_55a00(); break;
- case 0x2ae: run_55c00(); break;
- case 0x2af: run_55e00(); break;
- case 0x2b0: run_56000(); break;
- case 0x2b1: run_56200(); break;
- case 0x2b2: run_56400(); break;
- case 0x2b3: run_56600(); break;
- case 0x2b4: run_56800(); break;
- case 0x2b5: run_56a00(); break;
- case 0x2b6: run_56c00(); break;
- case 0x2b7: run_56e00(); break;
- case 0x2b8: run_57000(); break;
- case 0x2b9: run_57200(); break;
- case 0x2ba: run_57400(); break;
- case 0x2bb: run_57600(); break;
- case 0x2bc: run_57800(); break;
- case 0x2bd: run_57a00(); break;
- case 0x2be: run_57c00(); break;
- case 0x2bf: run_57e00(); break;
- case 0x2c0: run_58000(); break;
- case 0x2c1: run_58200(); break;
- case 0x2c2: run_58400(); break;
- case 0x2c3: run_58600(); break;
- case 0x2c4: run_58800(); break;
- case 0x2c5: run_58a00(); break;
- case 0x2c6: run_58c00(); break;
- case 0x2c7: run_58e00(); break;
- case 0x2c8: run_59000(); break;
- case 0x2c9: run_59200(); break;
- case 0x2ca: run_59400(); break;
- case 0x2cb: run_59600(); break;
- case 0x2cc: run_59800(); break;
- case 0x2cd: run_59a00(); break;
- case 0x2ce: run_59c00(); break;
- case 0x2cf: run_59e00(); break;
- case 0x2d0: run_5a000(); break;
- case 0x2d1: run_5a200(); break;
- case 0x2d2: run_5a400(); break;
- case 0x2d3: run_5a600(); break;
- case 0x2d4: run_5a800(); break;
- case 0x2d5: run_5aa00(); break;
- case 0x2d6: run_5ac00(); break;
- case 0x2d7: run_5ae00(); break;
- case 0x2d8: run_5b000(); break;
- case 0x2d9: run_5b200(); break;
- case 0x2da: run_5b400(); break;
- case 0x2db: run_5b600(); break;
- case 0x2dc: run_5b800(); break;
- case 0x2dd: run_5ba00(); break;
- case 0x2de: run_5bc00(); break;
- case 0x2df: run_5be00(); break;
- case 0x2e0: run_5c000(); break;
- case 0x2e1: run_5c200(); break;
- case 0x2e2: run_5c400(); break;
- case 0x2e3: run_5c600(); break;
- case 0x2e4: run_5c800(); break;
- case 0x2e5: run_5ca00(); break;
- case 0x2e6: run_5cc00(); break;
- case 0x2e7: run_5ce00(); break;
- case 0x2e8: run_5d000(); break;
- case 0x2e9: run_5d200(); break;
- case 0x2ea: run_5d400(); break;
- case 0x2eb: run_5d600(); break;
- case 0x2ec: run_5d800(); break;
- case 0x2ed: run_5da00(); break;
- case 0x2ee: run_5dc00(); break;
- case 0x2ef: run_5de00(); break;
- case 0x2f0: run_5e000(); break;
- case 0x2f1: run_5e200(); break;
- case 0x2f2: run_5e400(); break;
- case 0x2f3: run_5e600(); break;
- case 0x2f4: run_5e800(); break;
- case 0x2f5: run_5ea00(); break;
- case 0x2f6: run_5ec00(); break;
- case 0x2f7: run_5ee00(); break;
- case 0x2f8: run_5f000(); break;
- case 0x2f9: run_5f200(); break;
- case 0x2fa: run_5f400(); break;
- case 0x2fb: run_5f600(); break;
- case 0x2fc: run_5f800(); break;
- case 0x2fd: run_5fa00(); break;
- case 0x2fe: run_5fc00(); break;
- case 0x2ff: run_5fe00(); break;
- case 0x300: run_60000(); break;
- case 0x301: run_60200(); break;
- case 0x302: run_60400(); break;
- case 0x303: run_60600(); break;
- case 0x304: run_60800(); break;
- case 0x305: run_60a00(); break;
- case 0x306: run_60c00(); break;
- case 0x307: run_60e00(); break;
- case 0x308: run_61000(); break;
- case 0x309: run_61200(); break;
- case 0x30a: run_61400(); break;
- case 0x30b: run_61600(); break;
- case 0x30c: run_61800(); break;
- case 0x30d: run_61a00(); break;
- case 0x30e: run_61c00(); break;
- case 0x30f: run_61e00(); break;
- case 0x310: run_62000(); break;
- case 0x311: run_62200(); break;
- case 0x312: run_62400(); break;
- case 0x313: run_62600(); break;
- case 0x314: run_62800(); break;
- case 0x315: run_62a00(); break;
- case 0x316: run_62c00(); break;
- case 0x317: run_62e00(); break;
- case 0x318: run_63000(); break;
- case 0x319: run_63200(); break;
- case 0x31a: run_63400(); break;
- case 0x31b: run_63600(); break;
- case 0x31c: run_63800(); break;
- case 0x31d: run_63a00(); break;
- case 0x31e: run_63c00(); break;
- case 0x31f: run_63e00(); break;
- case 0x320: run_64000(); break;
- case 0x321: run_64200(); break;
- case 0x322: run_64400(); break;
- case 0x323: run_64600(); break;
- case 0x324: run_64800(); break;
- case 0x325: run_64a00(); break;
- case 0x326: run_64c00(); break;
- case 0x327: run_64e00(); break;
- case 0x328: run_65000(); break;
- case 0x329: run_65200(); break;
- case 0x32a: run_65400(); break;
- case 0x32b: run_65600(); break;
- case 0x32c: run_65800(); break;
- case 0x32d: run_65a00(); break;
- case 0x32e: run_65c00(); break;
- case 0x32f: run_65e00(); break;
- case 0x330: run_66000(); break;
- case 0x331: run_66200(); break;
- case 0x332: run_66400(); break;
- case 0x333: run_66600(); break;
- case 0x334: run_66800(); break;
- case 0x335: run_66a00(); break;
- case 0x336: run_66c00(); break;
- case 0x337: run_66e00(); break;
- case 0x338: run_67000(); break;
- case 0x339: run_67200(); break;
- case 0x33a: run_67400(); break;
- case 0x33b: run_67600(); break;
- case 0x33c: run_67800(); break;
- case 0x33d: run_67a00(); break;
- case 0x33e: run_67c00(); break;
- case 0x33f: run_67e00(); break;
- case 0x340: run_68000(); break;
- case 0x341: run_68200(); break;
- case 0x342: run_68400(); break;
- case 0x343: run_68600(); break;
- case 0x344: run_68800(); break;
- case 0x345: run_68a00(); break;
- case 0x346: run_68c00(); break;
- case 0x347: run_68e00(); break;
- case 0x348: run_69000(); break;
- case 0x349: run_69200(); break;
- case 0x34a: run_69400(); break;
- case 0x34b: run_69600(); break;
- case 0x34c: run_69800(); break;
- case 0x34d: run_69a00(); break;
- case 0x34e: run_69c00(); break;
- case 0x34f: run_69e00(); break;
- case 0x350: run_6a000(); break;
- case 0x351: run_6a200(); break;
- case 0x352: run_6a400(); break;
- case 0x353: run_6a600(); break;
- case 0x354: run_6a800(); break;
- case 0x355: run_6aa00(); break;
- case 0x356: run_6ac00(); break;
- case 0x357: run_6ae00(); break;
- case 0x358: run_6b000(); break;
- case 0x359: run_6b200(); break;
- case 0x35a: run_6b400(); break;
- case 0x35b: run_6b600(); break;
- case 0x35c: run_6b800(); break;
- case 0x35d: run_6ba00(); break;
- case 0x35e: run_6bc00(); break;
- case 0x35f: run_6be00(); break;
- case 0x360: run_6c000(); break;
- case 0x361: run_6c200(); break;
- case 0x362: run_6c400(); break;
+ switch(pc>>>11) {
+ case 0x20: run_10000(); break;
+ case 0x21: run_10800(); break;
+ case 0x22: run_11000(); break;
+ case 0x23: run_11800(); break;
+ case 0x24: run_12000(); break;
+ case 0x25: run_12800(); break;
+ case 0x26: run_13000(); break;
+ case 0x27: run_13800(); break;
+ case 0x28: run_14000(); break;
+ case 0x29: run_14800(); break;
+ case 0x2a: run_15000(); break;
+ case 0x2b: run_15800(); break;
+ case 0x2c: run_16000(); break;
+ case 0x2d: run_16800(); break;
+ case 0x2e: run_17000(); break;
+ case 0x2f: run_17800(); break;
+ case 0x30: run_18000(); break;
+ case 0x31: run_18800(); break;
+ case 0x32: run_19000(); break;
+ case 0x33: run_19800(); break;
+ case 0x34: run_1a000(); break;
+ case 0x35: run_1a800(); break;
+ case 0x36: run_1b000(); break;
+ case 0x37: run_1b800(); break;
+ case 0x38: run_1c000(); break;
+ case 0x39: run_1c800(); break;
+ case 0x3a: run_1d000(); break;
+ case 0x3b: run_1d800(); break;
+ case 0x3c: run_1e000(); break;
+ case 0x3d: run_1e800(); break;
+ case 0x3e: run_1f000(); break;
+ case 0x3f: run_1f800(); break;
+ case 0x40: run_20000(); break;
+ case 0x41: run_20800(); break;
+ case 0x42: run_21000(); break;
+ case 0x43: run_21800(); break;
+ case 0x44: run_22000(); break;
+ case 0x45: run_22800(); break;
+ case 0x46: run_23000(); break;
+ case 0x47: run_23800(); break;
+ case 0x48: run_24000(); break;
+ case 0x49: run_24800(); break;
+ case 0x4a: run_25000(); break;
+ case 0x4b: run_25800(); break;
+ case 0x4c: run_26000(); break;
+ case 0x4d: run_26800(); break;
+ case 0x4e: run_27000(); break;
+ case 0x4f: run_27800(); break;
+ case 0x50: run_28000(); break;
+ case 0x51: run_28800(); break;
+ case 0x52: run_29000(); break;
+ case 0x53: run_29800(); break;
+ case 0x54: run_2a000(); break;
+ case 0x55: run_2a800(); break;
+ case 0x56: run_2b000(); break;
+ case 0x57: run_2b800(); break;
+ case 0x58: run_2c000(); break;
+ case 0x59: run_2c800(); break;
+ case 0x5a: run_2d000(); break;
+ case 0x5b: run_2d800(); break;
+ case 0x5c: run_2e000(); break;
+ case 0x5d: run_2e800(); break;
+ case 0x5e: run_2f000(); break;
+ case 0x5f: run_2f800(); break;
+ case 0x60: run_30000(); break;
+ case 0x61: run_30800(); break;
+ case 0x62: run_31000(); break;
+ case 0x63: run_31800(); break;
+ case 0x64: run_32000(); break;
+ case 0x65: run_32800(); break;
+ case 0x66: run_33000(); break;
+ case 0x67: run_33800(); break;
+ case 0x68: run_34000(); break;
+ case 0x69: run_34800(); break;
+ case 0x6a: run_35000(); break;
+ case 0x6b: run_35800(); break;
+ case 0x6c: run_36000(); break;
+ case 0x6d: run_36800(); break;
+ case 0x6e: run_37000(); break;
+ case 0x6f: run_37800(); break;
+ case 0x70: run_38000(); break;
+ case 0x71: run_38800(); break;
+ case 0x72: run_39000(); break;
+ case 0x73: run_39800(); break;
+ case 0x74: run_3a000(); break;
+ case 0x75: run_3a800(); break;
+ case 0x76: run_3b000(); break;
+ case 0x77: run_3b800(); break;
+ case 0x78: run_3c000(); break;
+ case 0x79: run_3c800(); break;
+ case 0x7a: run_3d000(); break;
+ case 0x7b: run_3d800(); break;
+ case 0x7c: run_3e000(); break;
+ case 0x7d: run_3e800(); break;
+ case 0x7e: run_3f000(); break;
+ case 0x7f: run_3f800(); break;
+ case 0x80: run_40000(); break;
+ case 0x81: run_40800(); break;
+ case 0x82: run_41000(); break;
+ case 0x83: run_41800(); break;
+ case 0x84: run_42000(); break;
+ case 0x85: run_42800(); break;
+ case 0x86: run_43000(); break;
+ case 0x87: run_43800(); break;
+ case 0x88: run_44000(); break;
+ case 0x89: run_44800(); break;
+ case 0x8a: run_45000(); break;
+ case 0x8b: run_45800(); break;
+ case 0x8c: run_46000(); break;
+ case 0x8d: run_46800(); break;
+ case 0x8e: run_47000(); break;
+ case 0x8f: run_47800(); break;
+ case 0x90: run_48000(); break;
+ case 0x91: run_48800(); break;
+ case 0x92: run_49000(); break;
+ case 0x93: run_49800(); break;
+ case 0x94: run_4a000(); break;
+ case 0x95: run_4a800(); break;
+ case 0x96: run_4b000(); break;
+ case 0x97: run_4b800(); break;
+ case 0x98: run_4c000(); break;
+ case 0x99: run_4c800(); break;
+ case 0x9a: run_4d000(); break;
+ case 0x9b: run_4d800(); break;
+ case 0x9c: run_4e000(); break;
+ case 0x9d: run_4e800(); break;
+ case 0x9e: run_4f000(); break;
+ case 0x9f: run_4f800(); break;
+ case 0xa0: run_50000(); break;
+ case 0xa1: run_50800(); break;
+ case 0xa2: run_51000(); break;
+ case 0xa3: run_51800(); break;
+ case 0xa4: run_52000(); break;
+ case 0xa5: run_52800(); break;
+ case 0xa6: run_53000(); break;
+ case 0xa7: run_53800(); break;
+ case 0xa8: run_54000(); break;
+ case 0xa9: run_54800(); break;
+ case 0xaa: run_55000(); break;
+ case 0xab: run_55800(); break;
+ case 0xac: run_56000(); break;
+ case 0xad: run_56800(); break;
+ case 0xae: run_57000(); break;
+ case 0xaf: run_57800(); break;
+ case 0xb0: run_58000(); break;
+ case 0xb1: run_58800(); break;
+ case 0xb2: run_59000(); break;
+ case 0xb3: run_59800(); break;
+ case 0xb4: run_5a000(); break;
+ case 0xb5: run_5a800(); break;
+ case 0xb6: run_5b000(); break;
+ case 0xb7: run_5b800(); break;
+ case 0xb8: run_5c000(); break;
+ case 0xb9: run_5c800(); break;
+ case 0xba: run_5d000(); break;
+ case 0xbb: run_5d800(); break;
default: throw new ExecutionException("invalid address 0x" + Long.toString(this.pc&0xffffffffL,16) + ": r2: " + r2);
}
}
}
public AcmeCrossAssembler() {
- super(4096,65536);
- initPages(_data1,0x6c600,false);
- initPages(_data2,0x6c608,false);
- initPages(_data3,0x6d000,true);
- initPages(_data4,0x71548,false);
- initPages(_data5,0x73010,false);
- clearPages(0x7378c,0x48);
- clearPages(0x738b0,0x1012);
+ super(4194304,1);
+ initPages(_data1,0x5e000,false);
+ initPages(_data2,0x5e008,false);
+ initPages(_data3,0x5f000,true);
+ initPages(_data4,0x63ba0,false);
+ initPages(_data5,0x666c0,false);
+ clearPages(0x66c10,0x26);
+ clearPages(0x66ca8,0x392);
}
protected int entryPoint() { return 0x10400; }
- protected int heapStart() { return 0x778f8; }
- protected int gp() { return 0x7b010; }
+ protected int heapStart() { return 0x67af0; }
+ protected int gp() { return 0x6e6c0; }
public static void main(String[] args) throws Exception {
AcmeCrossAssembler me = new AcmeCrossAssembler();
- int status = me.run("Acme",args);
+ int status = me.run("jace.assembly.AcmeCrossAssembler",args);
System.exit(status);
}
@@ -91861,284 +71946,176 @@ public final class AcmeCrossAssembler extends UnixRuntime {
private static final java.util.Hashtable symbols = new java.util.Hashtable();
static {
- symbols.put("setgrent",new Integer(0x53c00));
- symbols.put("chroot",new Integer(0x4cc00));
- symbols.put("strcpy",new Integer(0x42e00));
- symbols.put("cliargs_get_rest",new Integer(0x16e00));
- symbols.put("flow_store_doloop_condition",new Integer(0x19600));
- symbols.put("fabs",new Integer(0x32a00));
- symbols.put("waitpid",new Integer(0x4ae00));
- symbols.put("vcpu_set_pc",new Integer(0x27e00));
- symbols.put("flow_parse_block_else_block",new Integer(0x19a00));
- symbols.put("Output_passinit",new Integer(0x27600));
- symbols.put("Input_until_terminator",new Integer(0x1d800));
- symbols.put("GetQuotedByte",new Integer(0x1c600));
- symbols.put("getgid",new Integer(0x496c4));
- symbols.put("sysconf",new Integer(0x4a400));
- symbols.put("printf",new Integer(0x3fc00));
- symbols.put("vsprintf",new Integer(0x65200));
- symbols.put("utime",new Integer(0x4a800));
- symbols.put("Input_skip_or_store_block",new Integer(0x1d400));
- symbols.put("getlogin",new Integer(0x54e00));
- symbols.put("recv",new Integer(0x4fe00));
- symbols.put("Input_skip_remainder",new Integer(0x1c800));
- symbols.put("connect",new Integer(0x4e200));
- symbols.put("ungetc",new Integer(0x6a800));
- symbols.put("GetByte",new Integer(0x1c000));
- symbols.put("safe_malloc",new Integer(0x1b400));
- symbols.put("geteuid",new Integer(0x496b4));
- symbols.put("symbol_fix_forward_anon_name",new Integer(0x30800));
- symbols.put("memmove",new Integer(0x5b600));
- symbols.put("keyword_is_65816mnemo",new Integer(0x24e00));
- symbols.put("snprintf",new Integer(0x41c00));
- symbols.put("pathconf",new Integer(0x4c800));
- symbols.put("Tree_easy_scan",new Integer(0x31000));
- symbols.put("mknod",new Integer(0x4ce00));
- symbols.put("getgrgid",new Integer(0x53800));
- symbols.put("dump_tree",new Integer(0x31400));
- symbols.put("getenv",new Integer(0x3e000));
- symbols.put("fchmod",new Integer(0x4c000));
- symbols.put("floor",new Integer(0x37600));
- symbols.put("getegid",new Integer(0x496d4));
- symbols.put("setpriority",new Integer(0x4e000));
- symbols.put("getpriority",new Integer(0x4de00));
- symbols.put("usleep",new Integer(0x4d200));
- symbols.put("typesystem_want_imm",new Integer(0x32000));
- symbols.put("getpagesize",new Integer(0x48b80));
- symbols.put("fchown",new Integer(0x4ba00));
- symbols.put("fgets",new Integer(0x59400));
- symbols.put("dirname",new Integer(0x55000));
- symbols.put("Section_finalize",new Integer(0x2e600));
- symbols.put("Throw_warning",new Integer(0x1ac00));
- symbols.put("memcpy",new Integer(0x48fdc));
- symbols.put("DynaBuf_to_lower",new Integer(0x18000));
- symbols.put("Throw_error",new Integer(0x1b000));
- symbols.put("ALU_any_result",new Integer(0x16400));
- symbols.put("readlink",new Integer(0x4b600));
- symbols.put("puts",new Integer(0x40400));
- symbols.put("dup2",new Integer(0x4ac00));
- symbols.put("mbrtowc",new Integer(0x66200));
- symbols.put("getpass",new Integer(0x54a00));
- symbols.put("getuid",new Integer(0x496a4));
- symbols.put("malloc",new Integer(0x3e800));
- symbols.put("isatty",new Integer(0x5a200));
- symbols.put("symbol_define",new Integer(0x30200));
- symbols.put("iswspace",new Integer(0x65e00));
- symbols.put("endpwent",new Integer(0x54800));
- symbols.put("sleep",new Integer(0x48af0));
- symbols.put("vsnprintf",new Integer(0x64e00));
- symbols.put("recvfrom",new Integer(0x4f800));
- symbols.put("strtoul",new Integer(0x5fc00));
- symbols.put("ACME_finalize",new Integer(0x11800));
- symbols.put("typesystem_force_address_statement",new Integer(0x31e00));
- symbols.put("gethostbyaddr",new Integer(0x53200));
- symbols.put("rmdir",new Integer(0x4a200));
- symbols.put("Input_append_keyword_to_global_dynabuf",new Integer(0x1dc00));
- symbols.put("socket",new Integer(0x4e400));
- symbols.put("select",new Integer(0x4fa00));
- symbols.put("readdir",new Integer(0x52600));
- symbols.put("lchown",new Integer(0x4bc00));
- symbols.put("setgroups",new Integer(0x50e00));
- symbols.put("fflush",new Integer(0x39a00));
- symbols.put("cliargs_safe_get_next",new Integer(0x16a00));
- symbols.put("ftruncate",new Integer(0x4d000));
- symbols.put("realpath",new Integer(0x4d800));
- symbols.put("keyword_is_6510mnemo",new Integer(0x23000));
- symbols.put("chown",new Integer(0x4b800));
- symbols.put("send",new Integer(0x4fc00));
- symbols.put("vcpu_check_and_set_reg_length",new Integer(0x17200));
- symbols.put("Output_init",new Integer(0x26e00));
- symbols.put("chmod",new Integer(0x4be00));
- symbols.put("alarm",new Integer(0x49a64));
- symbols.put("Parse_optional_block",new Integer(0x1b600));
- symbols.put("strtol",new Integer(0x43600));
- symbols.put("pipe",new Integer(0x4aa00));
- symbols.put("encoding_passinit",new Integer(0x18e00));
- symbols.put("uname",new Integer(0x55400));
- symbols.put("symbol_parse_definition",new Integer(0x2fc00));
- symbols.put("Output_start_segment",new Integer(0x27a00));
- symbols.put("accept",new Integer(0x4ea00));
- symbols.put("rint",new Integer(0x38000));
- symbols.put("basename",new Integer(0x55200));
- symbols.put("ALU_optional_defined_int",new Integer(0x15a00));
- symbols.put("output_set_output_filename",new Integer(0x26c00));
- symbols.put("DynaBuf_get_copy",new Integer(0x17a00));
- symbols.put("output_set_output_format",new Integer(0x26800));
- symbols.put("strtod",new Integer(0x68800));
- symbols.put("Throw_first_pass_warning",new Integer(0x1ae00));
- symbols.put("Parse_until_eob_or_eof",new Integer(0x1a400));
- symbols.put("sysctl",new Integer(0x4dc00));
- symbols.put("fstat",new Integer(0x62e00));
- symbols.put("fprintf",new Integer(0x3bc00));
- symbols.put("cputype_passinit",new Integer(0x17400));
- symbols.put("setpwent",new Integer(0x54600));
- symbols.put("bind",new Integer(0x4f000));
- symbols.put("inet_addr",new Integer(0x56200));
- symbols.put("mkfifo",new Integer(0x4d400));
- symbols.put("chdir",new Integer(0x4a600));
- symbols.put("Input_read_keyword",new Integer(0x1ec00));
- symbols.put("cputype_find",new Integer(0x17000));
- symbols.put("initgroups",new Integer(0x56600));
- symbols.put("Macro_parse_definition",new Integer(0x20600));
- symbols.put("endgrent",new Integer(0x53e00));
- symbols.put("setsockopt",new Integer(0x4ee00));
- symbols.put("fseek",new Integer(0x3d400));
- symbols.put("cos",new Integer(0x32800));
- symbols.put("memchr",new Integer(0x5b400));
- symbols.put("output_le16",new Integer(0x26000));
- symbols.put("umask",new Integer(0x49694));
- symbols.put("symbol_set_value",new Integer(0x2f600));
- symbols.put("symbol_find",new Integer(0x2f400));
- symbols.put("lstat",new Integer(0x4c200));
- symbols.put("sin",new Integer(0x32c00));
- symbols.put("setgid",new Integer(0x50a00));
- symbols.put("signal",new Integer(0x5ea00));
- symbols.put("output_8",new Integer(0x25e00));
- symbols.put("strncmp",new Integer(0x43000));
- symbols.put("DynaBuf_create",new Integer(0x17600));
- symbols.put("pow",new Integer(0x33400));
- symbols.put("keyword_is_6502mnemo",new Integer(0x22600));
- symbols.put("strncpy",new Integer(0x5f400));
- symbols.put("DynaBuf_add_string",new Integer(0x17e00));
- symbols.put("Input_read_filename",new Integer(0x1fc00));
- symbols.put("sync",new Integer(0x51e00));
- symbols.put("ALU_int_result",new Integer(0x15c00));
- symbols.put("sendto",new Integer(0x4f600));
- symbols.put("realloc",new Integer(0x40600));
- symbols.put("vcpu_get_statement_size",new Integer(0x28200));
- symbols.put("Section_passinit",new Integer(0x2e800));
- symbols.put("listen",new Integer(0x4f200));
- symbols.put("fork",new Integer(0x62c00));
- symbols.put("sscanf",new Integer(0x5f000));
- symbols.put("getgrent",new Integer(0x53a00));
- symbols.put("sigaction",new Integer(0x52200));
- symbols.put("fread",new Integer(0x3c600));
- symbols.put("inet_aton",new Integer(0x55e00));
- symbols.put("Input_read_and_lower_keyword",new Integer(0x1f400));
- symbols.put("symlink",new Integer(0x4b400));
- symbols.put("encoding_find",new Integer(0x19200));
- symbols.put("Tree_add_table",new Integer(0x30e00));
- symbols.put("DynaBuf_init",new Integer(0x18200));
- symbols.put("fopen",new Integer(0x3b800));
- symbols.put("memset",new Integer(0x48fec));
- symbols.put("main",new Integer(0x11c00));
- symbols.put("typesystem_want_addr",new Integer(0x32200));
- symbols.put("Output_end_segment",new Integer(0x27800));
- symbols.put("Output_fake",new Integer(0x25c00));
- symbols.put("add_node_to_tree",new Integer(0x30c00));
- symbols.put("pseudoopcodes_init",new Integer(0x2e000));
- symbols.put("DynaBuf_append",new Integer(0x17c00));
- symbols.put("matherr",new Integer(0x37c00));
- symbols.put("fclose",new Integer(0x39200));
- symbols.put("inet_ntoa",new Integer(0x52a00));
- symbols.put("getppid",new Integer(0x491bc));
- symbols.put("opendir",new Integer(0x52400));
- symbols.put("getgroups",new Integer(0x50000));
- symbols.put("keyword_is_c64dtv2mnemo",new Integer(0x23a00));
- symbols.put("getgrouplist",new Integer(0x56400));
- symbols.put("seteuid",new Integer(0x50800));
- symbols.put("keyword_is_65c02mnemo",new Integer(0x24400));
- symbols.put("putc",new Integer(0x40000));
- symbols.put("output_initmem",new Integer(0x26600));
- symbols.put("finite",new Integer(0x37400));
- symbols.put("herror",new Integer(0x53000));
- symbols.put("strcmp",new Integer(0x42c00));
- symbols.put("flow_forloop",new Integer(0x19400));
- symbols.put("shutdown",new Integer(0x4f400));
- symbols.put("tan",new Integer(0x32e00));
- symbols.put("ttyname",new Integer(0x52000));
- symbols.put("vfiprintf",new Integer(0x64a00));
- symbols.put("getpwuid",new Integer(0x54200));
- symbols.put("Input_read_zone_and_keyword",new Integer(0x1e400));
- symbols.put("dup",new Integer(0x4c600));
- symbols.put("copysign",new Integer(0x38800));
- symbols.put("getcwd",new Integer(0x4b000));
- symbols.put("Section_new_zone",new Integer(0x2e400));
- symbols.put("encoding_load",new Integer(0x19000));
- symbols.put("gethostbyname",new Integer(0x53400));
- symbols.put("getpwnam",new Integer(0x54000));
- symbols.put("getservbyname",new Integer(0x52c00));
- symbols.put("atan",new Integer(0x32400));
- symbols.put("gethostname",new Integer(0x55a00));
- symbols.put("sprintf",new Integer(0x42000));
- symbols.put("pseudoopcode_parse",new Integer(0x2e200));
- symbols.put("Tree_hard_scan",new Integer(0x31200));
- symbols.put("strtof",new Integer(0x68a00));
- symbols.put("atexit",new Integer(0x38a00));
- symbols.put("cliargs_get_next",new Integer(0x16600));
- symbols.put("output_le32",new Integer(0x26400));
- symbols.put("asin",new Integer(0x33200));
- symbols.put("setlocale",new Integer(0x5b000));
- symbols.put("getpeername",new Integer(0x50400));
- symbols.put("Throw_serious_error",new Integer(0x1b200));
- symbols.put("nanf",new Integer(0x66a00));
- symbols.put("cliargs_init",new Integer(0x16c00));
- symbols.put("scalbn",new Integer(0x38400));
- symbols.put("vfork",new Integer(0x4ca00));
- symbols.put("ALU_liberal_int",new Integer(0x16200));
- symbols.put("symbols_vicelabels",new Integer(0x30600));
- symbols.put("fsync",new Integer(0x51200));
- symbols.put("Mnemo_init",new Integer(0x22400));
- symbols.put("fputc",new Integer(0x3c000));
- symbols.put("symbol_set_label",new Integer(0x2f800));
- symbols.put("DynaBuf_enlarge",new Integer(0x17800));
- symbols.put("getsockopt",new Integer(0x4ec00));
- symbols.put("typesystem_force_address_block",new Integer(0x31c00));
- symbols.put("hstrerror",new Integer(0x52e00));
- symbols.put("vcpu_end_statement",new Integer(0x28400));
- symbols.put("nan",new Integer(0x37e00));
- symbols.put("Macro_parse_call",new Integer(0x20a00));
- symbols.put("encoding_encode_char",new Integer(0x18c00));
- symbols.put("Input_new_file",new Integer(0x1be00));
- symbols.put("localeconv",new Integer(0x5b200));
- symbols.put("Tree_dump_forest",new Integer(0x31800));
- symbols.put("Bug_found",new Integer(0x1b800));
- symbols.put("Output_save_file",new Integer(0x27000));
- symbols.put("fwrite",new Integer(0x3dc00));
- symbols.put("vcpu_read_pc",new Integer(0x28000));
- symbols.put("access",new Integer(0x4a000));
- symbols.put("ALU_any_int",new Integer(0x15e00));
- symbols.put("notreallypo_setpc",new Integer(0x2de00));
- symbols.put("getdents",new Integer(0x4c400));
- symbols.put("Input_accept_comma",new Integer(0x20000));
- symbols.put("exit",new Integer(0x38e00));
- symbols.put("klogctl",new Integer(0x4d600));
- symbols.put("typesystem_says_address",new Integer(0x31a00));
- symbols.put("getgrnam",new Integer(0x53600));
- symbols.put("make_hash",new Integer(0x30a00));
- symbols.put("output_prefer_cbm_file_format",new Integer(0x26a00));
- symbols.put("AnyOS_entry",new Integer(0x28600));
- symbols.put("Macro_init",new Integer(0x20400));
- symbols.put("ALU_init",new Integer(0x15800));
- symbols.put("getpwent",new Integer(0x54400));
- symbols.put("daemon",new Integer(0x55c00));
- symbols.put("strlen",new Integer(0x10268));
- symbols.put("open",new Integer(0x63000));
- symbols.put("Input_get_force_bit",new Integer(0x20200));
- symbols.put("fputs",new Integer(0x59a00));
- symbols.put("setsid",new Integer(0x51000));
- symbols.put("setegid",new Integer(0x50c00));
- symbols.put("closedir",new Integer(0x52800));
- symbols.put("cliargs_handle_options",new Integer(0x16800));
- symbols.put("acos",new Integer(0x33000));
- symbols.put("output_le24",new Integer(0x26200));
- symbols.put("vasprintf",new Integer(0x54c00));
- symbols.put("Input_ensure_EOS",new Integer(0x1ce00));
- symbols.put("setuid",new Integer(0x50600));
- symbols.put("mkdir",new Integer(0x49e00));
- symbols.put("ALU_defined_int",new Integer(0x16000));
- symbols.put("wcrtomb",new Integer(0x6ac00));
- symbols.put("close",new Integer(0x62a00));
- symbols.put("symbols_list",new Integer(0x30400));
- symbols.put("flow_parse_and_close_file",new Integer(0x19c00));
- symbols.put("flow_doloop",new Integer(0x19800));
- symbols.put("_call_helper",new Integer(0x10284));
- symbols.put("vfprintf",new Integer(0x48000));
- symbols.put("fputwc",new Integer(0x65c00));
- symbols.put("raise",new Integer(0x5e800));
- symbols.put("free",new Integer(0x3ea00));
- symbols.put("getsockname",new Integer(0x50200));
+ symbols.put("strcpy",Integer.valueOf(0x51800));
+ symbols.put("cliargs_get_rest",Integer.valueOf(0x1b400));
+ symbols.put("flow_store_doloop_condition",Integer.valueOf(0x1e600));
+ symbols.put("fabs",Integer.valueOf(0x43600));
+ symbols.put("typesystem_want_nonaddr",Integer.valueOf(0x42c00));
+ symbols.put("vcpu_set_pc",Integer.valueOf(0x36800));
+ symbols.put("section_new_cheap_scope",Integer.valueOf(0x3fc00));
+ symbols.put("check_ifdef_condition",Integer.valueOf(0x1e000));
+ symbols.put("input_read_and_lower_keyword",Integer.valueOf(0x26e00));
+ symbols.put("printf",Integer.valueOf(0x4f200));
+ symbols.put("throw_message",Integer.valueOf(0x1fc00));
+ symbols.put("outbuf_set_outfile_limit",Integer.valueOf(0x34c00));
+ symbols.put("input_skip_remainder",Integer.valueOf(0x23800));
+ symbols.put("GetByte",Integer.valueOf(0x23000));
+ symbols.put("safe_malloc",Integer.valueOf(0x20200));
+ symbols.put("output_get_xor",Integer.valueOf(0x36400));
+ symbols.put("symbol_fix_forward_anon_name",Integer.valueOf(0x41800));
+ symbols.put("memmove",Integer.valueOf(0x5ae00));
+ symbols.put("flow_do_while",Integer.valueOf(0x1ea00));
+ symbols.put("input_unescape_dynabuf",Integer.valueOf(0x24c00));
+ symbols.put("keyword_is_r65c02_mnemo",Integer.valueOf(0x2ea00));
+ symbols.put("section_new",Integer.valueOf(0x3fa00));
+ symbols.put("parser_set_nowarn_prefix",Integer.valueOf(0x1f800));
+ symbols.put("input_quoted_to_dynabuf",Integer.valueOf(0x24800));
+ symbols.put("output_passinit",Integer.valueOf(0x35c00));
+ symbols.put("dynabuf_enlarge",Integer.valueOf(0x1c000));
+ symbols.put("parser_change_nowarn_block_flag",Integer.valueOf(0x1f400));
+ symbols.put("keyword_is_w65c02_mnemo",Integer.valueOf(0x2f800));
+ symbols.put("getenv",Integer.valueOf(0x4d800));
+ symbols.put("floor",Integer.valueOf(0x48200));
+ symbols.put("input_readscopeandsymbolname",Integer.valueOf(0x26200));
+ symbols.put("parser_set_addr_prefix",Integer.valueOf(0x1f600));
+ symbols.put("pseudopc_end_all",Integer.valueOf(0x37400));
+ symbols.put("parse_assignment",Integer.valueOf(0x1fa00));
+ symbols.put("flow_store_while_condition",Integer.valueOf(0x1e800));
+ symbols.put("getpagesize",Integer.valueOf(0x56fd0));
+ symbols.put("outputfile_set_filename",Integer.valueOf(0x35200));
+ symbols.put("keyword_is_65ce02_mnemo",Integer.valueOf(0x30600));
+ symbols.put("input_read_keyword",Integer.valueOf(0x26600));
+ symbols.put("keyword_is_4502_mnemo",Integer.valueOf(0x31400));
+ symbols.put("memcpy",Integer.valueOf(0x56fe0));
+ symbols.put("ALU_any_result",Integer.valueOf(0x1aa00));
+ symbols.put("output_setdefault",Integer.valueOf(0x34800));
+ symbols.put("puts",Integer.valueOf(0x4f800));
+ symbols.put("malloc",Integer.valueOf(0x4de00));
+ symbols.put("isatty",Integer.valueOf(0x5a400));
+ symbols.put("keyword_is_65816_mnemo",Integer.valueOf(0x33000));
+ symbols.put("symbol_define",Integer.valueOf(0x41200));
+ symbols.put("outbuf_set_outfile_start",Integer.valueOf(0x34a00));
+ symbols.put("macro_parse_call",Integer.valueOf(0x28800));
+ symbols.put("keyword_is_nmos6502_mnemo",Integer.valueOf(0x2c000));
+ symbols.put("ACME_finalize",Integer.valueOf(0x12000));
+ symbols.put("output_set_xor",Integer.valueOf(0x36600));
+ symbols.put("input_accept_comma",Integer.valueOf(0x27c00));
+ symbols.put("parse_until_eob_or_eof",Integer.valueOf(0x20800));
+ symbols.put("input_read_input_filename",Integer.valueOf(0x27800));
+ symbols.put("tree_hard_scan",Integer.valueOf(0x42800));
+ symbols.put("fflush",Integer.valueOf(0x4a600));
+ symbols.put("dynabuf_add_string",Integer.valueOf(0x1c600));
+ symbols.put("cliargs_safe_get_next",Integer.valueOf(0x1b000));
+ symbols.put("encoding_load_from_file",Integer.valueOf(0x1da00));
+ symbols.put("dynabuf_append",Integer.valueOf(0x1c400));
+ symbols.put("keyword_is_6502_mnemo",Integer.valueOf(0x2b200));
+ symbols.put("vcpu_check_and_set_reg_length",Integer.valueOf(0x1b800));
+ symbols.put("strtol",Integer.valueOf(0x52000));
+ symbols.put("encoding_passinit",Integer.valueOf(0x1d800));
+ symbols.put("rint",Integer.valueOf(0x48c00));
+ symbols.put("Throw_first_pass_warning",Integer.valueOf(0x21200));
+ symbols.put("outputfile_prefer_cbm_format",Integer.valueOf(0x35000));
+ symbols.put("input_read_output_filename",Integer.valueOf(0x27a00));
+ symbols.put("includepaths_open_ro",Integer.valueOf(0x28200));
+ symbols.put("fstat",Integer.valueOf(0x5ce00));
+ symbols.put("fprintf",Integer.valueOf(0x4b800));
+ symbols.put("cputype_passinit",Integer.valueOf(0x1ba00));
+ symbols.put("parse_optional_block",Integer.valueOf(0x21000));
+ symbols.put("cputype_find",Integer.valueOf(0x1b600));
+ symbols.put("pseudopc_end",Integer.valueOf(0x37200));
+ symbols.put("fseek",Integer.valueOf(0x4ce00));
+ symbols.put("output_save_file",Integer.valueOf(0x35600));
+ symbols.put("dynabuf_add_bytes",Integer.valueOf(0x1c800));
+ symbols.put("cos",Integer.valueOf(0x43400));
+ symbols.put("memchr",Integer.valueOf(0x5ac00));
+ symbols.put("output_le16",Integer.valueOf(0x22000));
+ symbols.put("symbol_find",Integer.valueOf(0x40c00));
+ symbols.put("sin",Integer.valueOf(0x43800));
+ symbols.put("pseudopc_unpseudo",Integer.valueOf(0x37600));
+ symbols.put("dynabuf_clear",Integer.valueOf(0x1be00));
+ symbols.put("output_8",Integer.valueOf(0x21c00));
+ symbols.put("strncmp",Integer.valueOf(0x51a00));
+ symbols.put("pow",Integer.valueOf(0x44000));
+ symbols.put("pseudopc_start",Integer.valueOf(0x37000));
+ symbols.put("realloc",Integer.valueOf(0x4fa00));
+ symbols.put("vcpu_get_statement_size",Integer.valueOf(0x36c00));
+ symbols.put("memcmp",Integer.valueOf(0x4ec00));
+ symbols.put("fread",Integer.valueOf(0x4c000));
+ symbols.put("encoding_find",Integer.valueOf(0x1dc00));
+ symbols.put("fopen",Integer.valueOf(0x4b600));
+ symbols.put("memset",Integer.valueOf(0x56ff0));
+ symbols.put("main",Integer.valueOf(0x12400));
+ symbols.put("typesystem_want_addr",Integer.valueOf(0x42e00));
+ symbols.put("symbol_fix_dynamic_name",Integer.valueOf(0x41c00));
+ symbols.put("outputfile_set_format",Integer.valueOf(0x34e00));
+ symbols.put("matherr",Integer.valueOf(0x48800));
+ symbols.put("fclose",Integer.valueOf(0x49e00));
+ symbols.put("output_start_segment",Integer.valueOf(0x36000));
+ symbols.put("keyword_is_m65_mnemo",Integer.valueOf(0x32200));
+ symbols.put("includepaths_add",Integer.valueOf(0x28000));
+ symbols.put("input_new_file",Integer.valueOf(0x22e00));
+ symbols.put("finite",Integer.valueOf(0x48000));
+ symbols.put("symbol_set_object",Integer.valueOf(0x40e00));
+ symbols.put("strcmp",Integer.valueOf(0x51600));
+ symbols.put("flow_forloop",Integer.valueOf(0x1e200));
+ symbols.put("tan",Integer.valueOf(0x43a00));
+ symbols.put("copysign",Integer.valueOf(0x49400));
+ symbols.put("atan",Integer.valueOf(0x43000));
+ symbols.put("sprintf",Integer.valueOf(0x50c00));
+ symbols.put("pseudoopcode_parse",Integer.valueOf(0x3f800));
+ symbols.put("atexit",Integer.valueOf(0x49600));
+ symbols.put("cliargs_get_next",Integer.valueOf(0x1ac00));
+ symbols.put("output_le32",Integer.valueOf(0x22800));
+ symbols.put("asin",Integer.valueOf(0x43e00));
+ symbols.put("cliargs_init",Integer.valueOf(0x1b200));
+ symbols.put("scalbn",Integer.valueOf(0x49000));
+ symbols.put("symbols_vicelabels",Integer.valueOf(0x41600));
+ symbols.put("output_be24",Integer.valueOf(0x22200));
+ symbols.put("symbol_set_force_bit",Integer.valueOf(0x41000));
+ symbols.put("fputc",Integer.valueOf(0x4ba00));
+ symbols.put("section_finalize",Integer.valueOf(0x3fe00));
+ symbols.put("keyword_is_65c02_mnemo",Integer.valueOf(0x2dc00));
+ symbols.put("vcpu_end_statement",Integer.valueOf(0x36e00));
+ symbols.put("nan",Integer.valueOf(0x48a00));
+ symbols.put("encoding_encode_char",Integer.valueOf(0x1d600));
+ symbols.put("config_default",Integer.valueOf(0x1f000));
+ symbols.put("dynabuf_get_copy",Integer.valueOf(0x1c200));
+ symbols.put("fwrite",Integer.valueOf(0x4d600));
+ symbols.put("vcpu_read_pc",Integer.valueOf(0x36a00));
+ symbols.put("ALU_any_int",Integer.valueOf(0x1a200));
+ symbols.put("notreallypo_setpc",Integer.valueOf(0x3f600));
+ symbols.put("input_ensure_EOS",Integer.valueOf(0x24000));
+ symbols.put("output_skip",Integer.valueOf(0x34600));
+ symbols.put("dynabuf_add_signed_long",Integer.valueOf(0x1ca00));
+ symbols.put("exit",Integer.valueOf(0x49a00));
+ symbols.put("output_be16",Integer.valueOf(0x21e00));
+ symbols.put("macro_parse_definition",Integer.valueOf(0x28400));
+ symbols.put("tree_easy_scan",Integer.valueOf(0x42400));
+ symbols.put("tree_dump_forest",Integer.valueOf(0x42a00));
+ symbols.put("pseudopc_get_context",Integer.valueOf(0x37800));
+ symbols.put("output_createbuffer",Integer.valueOf(0x35400));
+ symbols.put("AnyOS_entry",Integer.valueOf(0x37a00));
+ symbols.put("dynabuf_to_lower",Integer.valueOf(0x1cc00));
+ symbols.put("keyword_is_c64dtv2_mnemo",Integer.valueOf(0x2ce00));
+ symbols.put("strlen",Integer.valueOf(0x10268));
+ symbols.put("input_get_force_bit",Integer.valueOf(0x27e00));
+ symbols.put("input_append_symbol_name_to_global_dynabuf",Integer.valueOf(0x25800));
+ symbols.put("cliargs_handle_options",Integer.valueOf(0x1ae00));
+ symbols.put("acos",Integer.valueOf(0x43c00));
+ symbols.put("output_le24",Integer.valueOf(0x22400));
+ symbols.put("ALU_addrmode_int",Integer.valueOf(0x1a800));
+ symbols.put("section_passinit",Integer.valueOf(0x40000));
+ symbols.put("output_end_segment",Integer.valueOf(0x35e00));
+ symbols.put("output_object",Integer.valueOf(0x21800));
+ symbols.put("output_be32",Integer.valueOf(0x22600));
+ symbols.put("input_skip_or_store_block",Integer.valueOf(0x24e00));
+ symbols.put("ALU_defined_int",Integer.valueOf(0x1a400));
+ symbols.put("symbols_list",Integer.valueOf(0x41400));
+ symbols.put("parser_change_addr_block_flag",Integer.valueOf(0x1f200));
+ symbols.put("flow_parse_and_close_file",Integer.valueOf(0x1ee00));
+ symbols.put("_call_helper",Integer.valueOf(0x10284));
+ symbols.put("BUG",Integer.valueOf(0x21400));
+ symbols.put("free",Integer.valueOf(0x4e000));
}
public int lookupSymbol(String symbol) { Integer i = (Integer) symbols.get(symbol); return i==null ? -1 : i.intValue(); }
-
}
diff --git a/src/main/java/jace/assembly/AssemblyHandler.java b/src/main/java/jace/assembly/AssemblyHandler.java
index 5cc12b3..9e0f708 100644
--- a/src/main/java/jace/assembly/AssemblyHandler.java
+++ b/src/main/java/jace/assembly/AssemblyHandler.java
@@ -1,66 +1,89 @@
package jace.assembly;
+import java.nio.ByteBuffer;
+
import jace.Emulator;
+import jace.core.Computer;
import jace.core.RAM;
import jace.ide.CompileResult;
+import jace.ide.HeadlessProgram;
import jace.ide.LanguageHandler;
import jace.ide.Program;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.logging.Level;
-import java.util.logging.Logger;
/**
*
* @author blurry
*/
-public class AssemblyHandler implements LanguageHandler {
+public class AssemblyHandler implements LanguageHandler {
@Override
public String getNewDocumentContent() {
return "\t\t*= $300;\n\t\t!cpu 65c02;\n;--- Insert your code here ---\n";
}
@Override
- public CompileResult compile(Program proxy) {
+ public CompileResult compile(Program proxy) {
AcmeCompiler compiler = new AcmeCompiler();
compiler.compile(proxy);
return compiler;
}
- @Override
- public void execute(CompileResult lastResult) {
+ public void compileToRam(String code) {
+ HeadlessProgram prg = new HeadlessProgram(Program.DocumentType.assembly);
+ prg.setValue(code);
+
+ CompileResult lastResult = compile(prg);
if (lastResult.isSuccessful()) {
- try {
- boolean resume = false;
- if (Emulator.computer.isRunning()) {
- resume = true;
- Emulator.computer.pause();
- }
- RAM memory = Emulator.computer.getMemory();
- FileInputStream input = new FileInputStream(lastResult.getCompiledAsset());
- int startLSB = input.read();
- int startMSB = input.read();
- int pos = startLSB + startMSB << 8;
- Emulator.computer.getCpu().JSR(pos);
- int next;
- while ((next=input.read()) != -1) {
- memory.write(pos++, (byte) next, false, true);
- }
- if (resume) {
- Emulator.computer.resume();
- }
- } catch (IOException ex) {
- Logger.getLogger(AssemblyHandler.class.getName()).log(Level.SEVERE, null, ex);
- }
+ Emulator.withComputer(c -> {
+ RAM memory = c.getMemory();
+ ByteBuffer input = lastResult.getCompiledAsset();
+ input.rewind();
+ int startLSB = input.get();
+ int startMSB = input.get();
+ int start = startLSB + startMSB << 8;
+ System.out.printf("Storing assembled code to $%s%n", Integer.toHexString(start));
+ c.getCpu().whileSuspended(() -> {
+ int pos = start;
+ while (input.hasRemaining()) {
+ memory.write(pos++, input.get(), false, true);
+ }
+ });
+ });
+ }
+ }
+
+ @Override
+ public void execute(CompileResult lastResult) throws Exception {
+ if (lastResult.isSuccessful()) {
+ Computer c = Emulator.withComputer(c1 -> c1, null);
+
+ RAM memory = c.getMemory();
+ ByteBuffer input = lastResult.getCompiledAsset();
+ input.rewind();
+ int startLSB = input.get() & 0x0ff;
+ int startMSB = input.get() & 0x0ff;
+ int start = startLSB + startMSB << 8;
+ // System.out.printf("Executing code at $%s%n", Integer.toHexString(start));
+ c.getCpu().whileSuspended(() -> {
+ // System.out.printf("Storing assembled code to $%s%n", Integer.toHexString(start));
+ int pos = start;
+ while (input.hasRemaining()) {
+ memory.write(pos++, input.get(), false, true);
+ }
+ // System.out.printf("Issuing JSR to $%s%n", Integer.toHexString(start));
+ c.getCpu().JSR(start);
+ });
+ // });
+ } else {
+ System.err.println("Compilation failed");
+ lastResult.getErrors().forEach((line, message) -> System.err.printf("Line %d: %s%n", line, message));
+ lastResult.getOtherMessages().forEach(System.err::println);
+ throw new Exception("Compilation failed");
}
clean(lastResult);
}
@Override
- public void clean(CompileResult lastResult) {
- if (lastResult.getCompiledAsset() != null) {
- lastResult.getCompiledAsset().delete();
- }
+ public void clean(CompileResult lastResult) {
+ // Nothing to do here
}
}
diff --git a/src/main/java/jace/cheat/Cheats.java b/src/main/java/jace/cheat/Cheats.java
index 27db3fc..254fb40 100644
--- a/src/main/java/jace/cheat/Cheats.java
+++ b/src/main/java/jace/cheat/Cheats.java
@@ -1,31 +1,31 @@
-/*
- * Copyright (C) 2012 Brendan Robert (BLuRry) brendan.robert@gmail.com.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301 USA
- */
+/**
+* Copyright 2024 Brendan Robert
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+**/
+
package jace.cheat;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.Supplier;
+
import jace.apple2e.MOS65C02;
+import jace.config.DeviceEnum;
import jace.config.InvokableAction;
-import jace.core.Computer;
import jace.core.Device;
import jace.core.RAMEvent;
import jace.core.RAMListener;
-import java.util.HashSet;
-import java.util.Set;
/**
* Represents some combination of hacks that can be enabled or disabled through
@@ -34,13 +34,44 @@ import java.util.Set;
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
*/
public abstract class Cheats extends Device {
+ public static enum Cheat implements DeviceEnum {
+ Metacheat("Metacheat", MetaCheat.class, MetaCheat::new),
+ MontezumasRevenge("Montezuma's Revenge", MontezumasRevengeCheats.class, MontezumasRevengeCheats::new),
+ PrinceOfPersia("Prince of Persia", PrinceOfPersiaCheats.class, PrinceOfPersiaCheats::new),
+ ProgramIdentity("Identify program", ProgramIdentity.class, ProgramIdentity::new);
+
+ Supplier factory;
+ String name;
+ Class extends Cheats> clazz;
+
+ Cheat(String name, Class extends Cheats> clazz, Supplier factory) {
+ this.name = name;
+ this.clazz = clazz;
+ this.factory = factory;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public Cheats create() {
+ return factory.get();
+ }
+
+ @Override
+ public boolean isInstance(Cheats cheat) {
+ if (cheat == null) {
+ return false;
+ }
+ return clazz == cheat.getClass();
+ }
+ }
+
boolean cheatsActive = true;
Set listeners = new HashSet<>();
-
- public Cheats(Computer computer) {
- super(computer);
- }
-
+
@InvokableAction(name = "Toggle Cheats", alternatives = "cheat;Plug-in", defaultKeyMapping = "ctrl+shift+m")
public void toggleCheats() {
cheatsActive = !cheatsActive;
@@ -51,36 +82,36 @@ public abstract class Cheats extends Device {
}
}
- public RAMListener bypassCode(int address, int addressEnd) {
+ public RAMListener bypassCode(String name, int address, int addressEnd) {
int noOperation = MOS65C02.COMMAND.NOP.ordinal();
- return addCheat(RAMEvent.TYPE.READ, (e) -> e.setNewValue(noOperation), address, addressEnd);
+ return addCheat(name, RAMEvent.TYPE.READ, (e) -> e.setNewValue(noOperation), address, addressEnd);
}
- public RAMListener forceValue(int value, int... address) {
- return addCheat(RAMEvent.TYPE.ANY, (e) -> e.setNewValue(value), address);
+ public RAMListener forceValue(String name, int value, int... address) {
+ return addCheat(name, RAMEvent.TYPE.ANY, (e) -> e.setNewValue(value), address);
}
- public RAMListener forceValue(int value, boolean auxFlag, int... address) {
- return addCheat(RAMEvent.TYPE.ANY, auxFlag, (e) -> e.setNewValue(value), address);
+ public RAMListener forceValue(String name, int value, Boolean auxFlag, int... address) {
+ return addCheat(name, RAMEvent.TYPE.ANY, auxFlag, (e) -> e.setNewValue(value), address);
}
- public RAMListener addCheat(RAMEvent.TYPE type, RAMEvent.RAMEventHandler handler, int... address) {
+ public RAMListener addCheat(String name, RAMEvent.TYPE type, RAMEvent.RAMEventHandler handler, int... address) {
RAMListener listener;
if (address.length == 1) {
- listener = computer.getMemory().observe(type, address[0], handler);
+ listener = getMemory().observe(getName() + ": " + name, type, address[0], handler);
} else {
- listener = computer.getMemory().observe(type, address[0], address[1], handler);
+ listener = getMemory().observe(getName() + ": " + name, type, address[0], address[1], handler);
}
listeners.add(listener);
return listener;
}
- public RAMListener addCheat(RAMEvent.TYPE type, boolean auxFlag, RAMEvent.RAMEventHandler handler, int... address) {
+ public RAMListener addCheat(String name, RAMEvent.TYPE type, Boolean auxFlag, RAMEvent.RAMEventHandler handler, int... address) {
RAMListener listener;
if (address.length == 1) {
- listener = computer.getMemory().observe(type, address[0], auxFlag, handler);
+ listener = getMemory().observe(getName() + ": " + name, type, address[0], auxFlag, handler);
} else {
- listener = computer.getMemory().observe(type, address[0], address[1], auxFlag, handler);
+ listener = getMemory().observe(getName() + ": " + name, type, address[0], address[1], auxFlag, handler);
}
listeners.add(listener);
return listener;
@@ -101,13 +132,13 @@ public abstract class Cheats extends Device {
protected void unregisterListeners() {
listeners.stream().forEach((l) -> {
- computer.getMemory().removeListener(l);
+ getMemory().removeListener(l);
});
listeners.clear();
}
public void removeListener(RAMListener l) {
- computer.getMemory().removeListener(l);
+ getMemory().removeListener(l);
listeners.remove(l);
}
diff --git a/src/main/java/jace/cheat/DynamicCheat.java b/src/main/java/jace/cheat/DynamicCheat.java
index 1f1a1be..608ed11 100644
--- a/src/main/java/jace/cheat/DynamicCheat.java
+++ b/src/main/java/jace/cheat/DynamicCheat.java
@@ -9,7 +9,6 @@ import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.util.Callback;
-import javax.script.ScriptException;
/**
*
@@ -21,22 +20,23 @@ public class DynamicCheat extends RAMListener {
StringProperty expression;
BooleanProperty active;
StringProperty name;
+ String cheatName;
Callback expressionCallback;
- public DynamicCheat(int address, String expr) {
- super(RAMEvent.TYPE.ANY, RAMEvent.SCOPE.ADDRESS, RAMEvent.VALUE.ANY);
+ public DynamicCheat(String cheatName, int address, int holdValue) {
+ super(cheatName, RAMEvent.TYPE.ANY, RAMEvent.SCOPE.ADDRESS, RAMEvent.VALUE.ANY);
id = (int) (Math.random() * 10000000);
addr = new SimpleIntegerProperty(address);
- expression = new SimpleStringProperty(expr);
+ expression = new SimpleStringProperty(String.valueOf(holdValue));
+ isHold = true;
active = new SimpleBooleanProperty(false);
name = new SimpleStringProperty("Untitled");
- expression.addListener((param, oldValue, newValue) -> {
- expressionCallback = parseExpression(newValue);
- });
- expressionCallback = parseExpression(expr);
+ expressionCallback = (RAMEvent e) -> holdValue;
doConfig();
}
+ boolean isHold = false;
+
@Override
protected void doConfig() {
if (addr != null) {
@@ -73,29 +73,6 @@ public class DynamicCheat extends RAMListener {
return expression;
}
- private Callback parseExpression(String expr) {
- String functionName = "processCheat" + id;
- String functionBody = "function " + functionName + "(old,val){" + (expr.contains("return") ? expr : "return " + expr) + "}";
- try {
- MetaCheat.NASHORN_ENGINE.eval(functionBody);
- return (RAMEvent e) -> {
- try {
- Object result = MetaCheat.NASHORN_INVOCABLE.invokeFunction(functionName, e.getOldValue(), e.getNewValue());
- if (result instanceof Number) {
- return ((Number) result).intValue();
- } else {
- System.err.println("Not able to handle non-numeric return value: " + result.getClass());
- return null;
- }
- } catch (ScriptException | NoSuchMethodException ex) {
- return null;
- }
- };
- } catch (ScriptException ex) {
- return null;
- }
- }
-
public static String escape(String in) {
return in.replaceAll(";", "~~").replaceAll("\n","\\n");
}
@@ -106,18 +83,19 @@ public class DynamicCheat extends RAMListener {
public static final String DELIMITER = ";";
public String serialize() {
- return escape(name.get()) + DELIMITER
+ return escape(cheatName) + DELIMITER + escape(name.get()) + DELIMITER
+ escape("$"+Integer.toHexString(addr.get())) + DELIMITER
+ escape(expression.get());
}
static public DynamicCheat deserialize(String in) {
String[] parts = in.split(DELIMITER);
- String name = unescape(parts[0]);
- Integer addr = Integer.parseInt(parts[1].substring(1), 16);
- String expr = unescape(parts[2]);
+ String cheatName = unescape(parts[0]);
+ String name = unescape(parts[1]);
+ Integer addr = Integer.parseInt(parts[2].substring(1), 16);
+ String expr = unescape(parts[3]);
- DynamicCheat out = new DynamicCheat(addr, expr);
+ DynamicCheat out = new DynamicCheat(cheatName, addr, Integer.parseInt(expr));
out.name.set(name);
return out;
}
diff --git a/src/main/java/jace/cheat/MemoryCell.java b/src/main/java/jace/cheat/MemoryCell.java
index 82e01ec..79aa70d 100644
--- a/src/main/java/jace/cheat/MemoryCell.java
+++ b/src/main/java/jace/cheat/MemoryCell.java
@@ -6,6 +6,7 @@
package jace.cheat;
import java.util.ArrayList;
+
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
@@ -13,7 +14,6 @@ import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
-import javafx.scene.shape.Shape;
/**
*
@@ -32,6 +32,10 @@ public class MemoryCell implements Comparable {
public ObservableList writeInstructions = FXCollections.observableList(new ArrayList<>());
public ObservableList writeInstructionsDisassembly = FXCollections.observableArrayList(new ArrayList<>());
public ObservableList execInstructionsDisassembly = FXCollections.observableArrayList(new ArrayList<>());
+ private int x;
+ private int y;
+ private int width;
+ private int height;
public static void setListener(ChangeListener l) {
listener = l;
@@ -46,22 +50,44 @@ public class MemoryCell implements Comparable {
value.addListener(changeListener);
}
+ public void setRect(int x, int y, int w, int h) {
+ this.x = x;
+ this.y = y;
+ this.width = w;
+ this.height = h;
+ }
+
+ public int getX() {
+ return x;
+ }
+
+ public int getY() {
+ return y;
+ }
+
+ public int getWidth() {
+ return width;
+ }
+
+ public int getHeight() {
+ return height;
+ }
+
@Override
public int compareTo(MemoryCell o) {
return address - o.address;
}
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof MemoryCell) {
+ MemoryCell om = (MemoryCell) o;
+ return address == om.address || (x == om.x && y == om.y);
+ }
+ return false;
+ }
+
public boolean hasCounts() {
return hasCount.get();
}
-
- private Shape shape;
-
- public void setShape(Shape s) {
- shape = s;
- }
-
- public Shape getShape() {
- return shape;
- }
}
diff --git a/src/main/java/jace/cheat/MetaCheat.java b/src/main/java/jace/cheat/MetaCheat.java
index 54e9f6c..ef7bf70 100644
--- a/src/main/java/jace/cheat/MetaCheat.java
+++ b/src/main/java/jace/cheat/MetaCheat.java
@@ -1,14 +1,5 @@
package jace.cheat;
-import jace.Emulator;
-import jace.JaceApplication;
-import jace.core.CPU;
-import jace.core.Computer;
-import jace.core.RAM;
-import jace.core.RAMEvent;
-import jace.core.RAMListener;
-import jace.state.State;
-import jace.ui.MetacheatUI;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
@@ -19,6 +10,14 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
+
+import jace.Emulator;
+import jace.JaceApplication;
+import jace.core.CPU;
+import jace.core.RAMEvent;
+import jace.core.RAMListener;
+import jace.state.State;
+import jace.ui.MetacheatUI;
import javafx.application.Platform;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.Property;
@@ -28,20 +27,13 @@ import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
-import javax.script.Invocable;
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineManager;
public class MetaCheat extends Cheats {
-
- static final ScriptEngine NASHORN_ENGINE = new ScriptEngineManager().getEngineByName("nashorn");
- static Invocable NASHORN_INVOCABLE = (Invocable) NASHORN_ENGINE;
-
- public static enum SearchType {
+ public enum SearchType {
VALUE, TEXT, CHANGE
}
- public static enum SearchChangeType {
+ public enum SearchChangeType {
NO_CHANGE, ANY_CHANGE, LESS, GREATER, AMOUNT
}
@@ -72,7 +64,7 @@ public class MetaCheat extends Cheats {
public int historyLength = 10;
private int startAddress = 0;
- private int endAddress = 0x0AFFF;
+ private int endAddress = 0x0BFFF;
private final StringProperty startAddressProperty = new SimpleStringProperty(Integer.toHexString(startAddress));
private final StringProperty endAddressProperty = new SimpleStringProperty(Integer.toHexString(endAddress));
private boolean byteSized = true;
@@ -85,17 +77,16 @@ public class MetaCheat extends Cheats {
private final ObservableList resultList = FXCollections.observableArrayList();
private final ObservableList snapshotList = FXCollections.observableArrayList();
- public MetaCheat(Computer computer) {
- super(computer);
+ public MetaCheat() {
addNumericValidator(startAddressProperty);
addNumericValidator(endAddressProperty);
addNumericValidator(searchValueProperty);
addNumericValidator(changeByProperty);
startAddressProperty.addListener((prop, oldVal, newVal) -> {
- startAddress = Math.max(0, Math.min(65535, Integer.parseInt(newVal, 16)));
+ startAddress = Math.max(0, Math.min(65535, parseInt(newVal)));
});
endAddressProperty.addListener((prop, oldVal, newVal) -> {
- endAddress = Math.max(0, Math.min(65535, Integer.parseInt(newVal, 16)));
+ endAddress = Math.max(0, Math.min(65535, parseInt(newVal)));
});
}
@@ -139,24 +130,24 @@ public class MetaCheat extends Cheats {
public void addCheat(DynamicCheat cheat) {
cheatList.add(cheat);
- computer.getMemory().addListener(cheat);
+ getMemory().addListener(cheat);
cheat.addressProperty().addListener((prop, oldVal, newVal) -> {
- computer.getMemory().removeListener(cheat);
+ getMemory().removeListener(cheat);
cheat.doConfig();
- computer.getMemory().addListener(cheat);
+ getMemory().addListener(cheat);
});
}
public void removeCheat(DynamicCheat cheat) {
cheat.active.set(false);
- computer.getMemory().removeListener(cheat);
+ getMemory().removeListener(cheat);
cheatList.remove(cheat);
}
@Override
protected void unregisterListeners() {
super.unregisterListeners();
- cheatList.stream().forEach(computer.getMemory()::removeListener);
+ cheatList.forEach(getMemory()::removeListener);
}
@Override
@@ -167,7 +158,7 @@ public class MetaCheat extends Cheats {
@Override
public void detach() {
super.detach();
- ui.detach();
+ JaceApplication.getApplication().closeMetacheat();
}
@Override
@@ -230,54 +221,63 @@ public class MetaCheat extends Cheats {
}
public void newSearch() {
- RAM memory = Emulator.computer.getMemory();
- resultList.clear();
- int compare = parseInt(searchValueProperty.get());
- for (int i = 0; i < 0x10000; i++) {
- boolean signed = signedProperty.get();
- int val
- = byteSized
- ? signed ? memory.readRaw(i) : memory.readRaw(i) & 0x0ff
- : signed ? memory.readWordRaw(i) : memory.readWordRaw(i) & 0x0ffff;
- if (!searchType.equals(SearchType.VALUE) || val == compare) {
- SearchResult result = new SearchResult(i, val);
- resultList.add(result);
+ Emulator.withMemory(memory -> {
+ resultList.clear();
+ int compare = parseInt(searchValueProperty.get());
+ for (int i = 0; i < 0x10000; i++) {
+ boolean signed = signedProperty.get();
+ int val
+ = byteSized
+ ? signed ? memory.readRaw(i) : memory.readRaw(i) & 0x0ff
+ : signed ? memory.readWordRaw(i) : memory.readWordRaw(i) & 0x0ffff;
+ if (!searchType.equals(SearchType.VALUE) || val == compare) {
+ SearchResult result = new SearchResult(i, val);
+ resultList.add(result);
+ }
}
- }
+ });
}
public void performSearch() {
- RAM memory = Emulator.computer.getMemory();
- boolean signed = signedProperty.get();
- resultList.removeIf((SearchResult result) -> {
- int val = byteSized
- ? signed ? memory.readRaw(result.address) : memory.readRaw(result.address) & 0x0ff
- : signed ? memory.readWordRaw(result.address) : memory.readWordRaw(result.address) & 0x0ffff;
- int last = result.lastObservedValue;
- result.lastObservedValue = val;
- switch (searchType) {
- case VALUE:
- int compare = parseInt(searchValueProperty.get());
- return compare != val;
- case CHANGE:
- switch (searchChangeType) {
- case AMOUNT:
- int amount = parseInt(searchChangeByProperty().getValue());
- return (val - last) != amount;
- case GREATER:
- return val <= last;
- case ANY_CHANGE:
- return val == last;
- case LESS:
- return val >= last;
- case NO_CHANGE:
- return val != last;
+ Emulator.withMemory(memory -> {
+ boolean signed = signedProperty.get();
+ resultList.removeIf((SearchResult result) -> {
+ int val = byteSized
+ ? signed ? memory.readRaw(result.address) : memory.readRaw(result.address) & 0x0ff
+ : signed ? memory.readWordRaw(result.address) : memory.readWordRaw(result.address) & 0x0ffff;
+ int last = result.lastObservedValue;
+ result.lastObservedValue = val;
+ switch (searchType) {
+ case VALUE -> {
+ int compare = parseInt(searchValueProperty.get());
+ return compare != val;
}
- break;
- case TEXT:
- break;
- }
- return false;
+ case CHANGE -> {
+ switch (searchChangeType) {
+ case AMOUNT -> {
+ int amount = parseInt(searchChangeByProperty().getValue());
+ return (val - last) != amount;
+ }
+ case GREATER -> {
+ return val <= last;
+ }
+ case ANY_CHANGE -> {
+ return val == last;
+ }
+ case LESS -> {
+ return val >= last;
+ }
+ case NO_CHANGE -> {
+ return val != last;
+ }
+ }
+ }
+
+ case TEXT -> {
+ }
+ }
+ return false;
+ });
});
}
@@ -289,41 +289,36 @@ public class MetaCheat extends Cheats {
}
public void initMemoryView() {
- RAM memory = Emulator.computer.getMemory();
- for (int addr = getStartAddress(); addr <= getEndAddress(); addr++) {
- if (getMemoryCell(addr) == null) {
- MemoryCell cell = new MemoryCell();
- cell.address = addr;
- cell.value.set(memory.readRaw(addr));
- memoryCells.put(addr, cell);
+ Emulator.withMemory(memory -> {
+ for (int addr = getStartAddress(); addr <= getEndAddress(); addr++) {
+ if (getMemoryCell(addr) == null) {
+ MemoryCell cell = new MemoryCell();
+ cell.address = addr;
+ cell.value.set(memory.readRaw(addr));
+ memoryCells.put(addr, cell);
+ }
}
- }
- if (memoryViewListener == null) {
- memoryViewListener = memory.observe(RAMEvent.TYPE.ANY, startAddress, endAddress, this::processMemoryEvent);
- listeners.add(memoryViewListener);
- }
+ if (memoryViewListener == null) {
+ memoryViewListener = memory.observe("Metacheat memory viewer", RAMEvent.TYPE.ANY, startAddress, endAddress, this::processMemoryEvent);
+ listeners.add(memoryViewListener);
+ }
+ });
}
int fadeCounter = 0;
- int FADE_TIMER_VALUE = (int) (Emulator.computer.getMotherboard().getSpeedInHz() / 60);
+ int FADE_TIMER_VALUE = Emulator.withComputer(c-> (int) (c.getMotherboard().getSpeedInHz() / 60), 100);
@Override
public void tick() {
- computer.cpu.performSingleTrace();
+ Emulator.withComputer(c-> c.getCpu().performSingleTrace());
if (fadeCounter-- <= 0) {
fadeCounter = FADE_TIMER_VALUE;
memoryCells.values().stream()
- .filter((cell) -> cell.hasCounts())
+ .filter(MemoryCell::hasCounts)
.forEach((cell) -> {
- if (cell.execCount.get() > 0) {
- cell.execCount.set(Math.max(0, cell.execCount.get() - fadeRate));
- }
- if (cell.readCount.get() > 0) {
- cell.readCount.set(Math.max(0, cell.readCount.get() - fadeRate));
- }
- if (cell.writeCount.get() > 0) {
- cell.writeCount.set(Math.max(0, cell.writeCount.get() - fadeRate));
- }
+ cell.execCount.set(Math.max(0, cell.execCount.get() - fadeRate));
+ cell.readCount.set(Math.max(0, cell.readCount.get() - fadeRate));
+ cell.writeCount.set(Math.max(0, cell.writeCount.get() - fadeRate));
if (MemoryCell.listener != null) {
MemoryCell.listener.changed(null, cell, cell);
}
@@ -339,107 +334,90 @@ public class MetaCheat extends Cheats {
private void processMemoryEvent(RAMEvent e) {
MemoryCell cell = getMemoryCell(e.getAddress());
if (cell != null) {
- CPU cpu = Emulator.computer.getCpu();
- int pc = cpu.getProgramCounter();
- String trace = cpu.getLastTrace();
- switch (e.getType()) {
- case EXECUTE:
- cell.execInstructionsDisassembly.add(trace);
- if (cell.execInstructionsDisassembly.size() > historyLength) {
- cell.execInstructionsDisassembly.remove(0);
- }
- case READ_OPERAND:
- cell.execCount.set(Math.min(255, cell.execCount.get() + lightRate));
- break;
- case WRITE:
- cell.writeCount.set(Math.min(255, cell.writeCount.get() + lightRate));
- if (ui.isInspecting(cell.address)) {
- if (pendingInspectorUpdates.incrementAndGet() < 5) {
- Platform.runLater(() -> {
- pendingInspectorUpdates.decrementAndGet();
- cell.writeInstructions.add(pc);
- cell.writeInstructionsDisassembly.add(trace);
- if (cell.writeInstructions.size() > historyLength) {
- cell.writeInstructions.remove(0);
- cell.writeInstructionsDisassembly.remove(0);
- }
- });
+ Emulator.withComputer(c -> {
+ CPU cpu = c.getCpu();
+ int pc = cpu.getProgramCounter();
+ String trace = cpu.getLastTrace();
+ switch (e.getType()) {
+ case EXECUTE:
+ cell.execInstructionsDisassembly.add(trace);
+ if (cell.execInstructionsDisassembly.size() > historyLength) {
+ cell.execInstructionsDisassembly.remove(0);
}
- } else {
- cell.writeInstructions.add(cpu.getProgramCounter());
- cell.writeInstructionsDisassembly.add(cpu.getLastTrace());
- if (cell.writeInstructions.size() > historyLength) {
- cell.writeInstructions.remove(0);
- cell.writeInstructionsDisassembly.remove(0);
+ case READ_OPERAND:
+ cell.execCount.set(Math.min(255, cell.execCount.get() + lightRate));
+ break;
+ case WRITE:
+ cell.writeCount.set(Math.min(255, cell.writeCount.get() + lightRate));
+ if (ui.isInspecting(cell.address)) {
+ if (pendingInspectorUpdates.incrementAndGet() < 5) {
+ Platform.runLater(() -> {
+ pendingInspectorUpdates.decrementAndGet();
+ cell.writeInstructions.add(pc);
+ cell.writeInstructionsDisassembly.add(trace);
+ if (cell.writeInstructions.size() > historyLength) {
+ cell.writeInstructions.remove(0);
+ cell.writeInstructionsDisassembly.remove(0);
+ }
+ });
+ }
+ } else {
+ cell.writeInstructions.add(cpu.getProgramCounter());
+ cell.writeInstructionsDisassembly.add(cpu.getLastTrace());
+ if (cell.writeInstructions.size() > historyLength) {
+ cell.writeInstructions.remove(0);
+ cell.writeInstructionsDisassembly.remove(0);
+ }
}
- }
- break;
- default:
- cell.readCount.set(Math.min(255, cell.readCount.get() + lightRate));
- if (ui.isInspecting(cell.address)) {
- if (pendingInspectorUpdates.incrementAndGet() < 5) {
- Platform.runLater(() -> {
- pendingInspectorUpdates.decrementAndGet();
- cell.readInstructions.add(pc);
- cell.readInstructionsDisassembly.add(trace);
- if (cell.readInstructions.size() > historyLength) {
- cell.readInstructions.remove(0);
- cell.readInstructionsDisassembly.remove(0);
- }
- });
+ break;
+ default:
+ cell.readCount.set(Math.min(255, cell.readCount.get() + lightRate));
+ if (ui.isInspecting(cell.address)) {
+ if (pendingInspectorUpdates.incrementAndGet() < 5) {
+ Platform.runLater(() -> {
+ pendingInspectorUpdates.decrementAndGet();
+ cell.readInstructions.add(pc);
+ cell.readInstructionsDisassembly.add(trace);
+ if (cell.readInstructions.size() > historyLength) {
+ cell.readInstructions.remove(0);
+ cell.readInstructionsDisassembly.remove(0);
+ }
+ });
+ }
+ } else {
+ cell.readInstructions.add(cpu.getProgramCounter());
+ cell.readInstructionsDisassembly.add(cpu.getLastTrace());
+ if (cell.readInstructions.size() > historyLength) {
+ cell.readInstructions.remove(0);
+ cell.readInstructionsDisassembly.remove(0);
+ }
}
- } else {
- cell.readInstructions.add(cpu.getProgramCounter());
- cell.readInstructionsDisassembly.add(cpu.getLastTrace());
- if (cell.readInstructions.size() > historyLength) {
- cell.readInstructions.remove(0);
- cell.readInstructionsDisassembly.remove(0);
- }
- }
- }
- cell.value.set(e.getNewValue());
+ }
+ cell.value.set(e.getNewValue());
+ });
}
}
public void saveCheats(File saveFile) {
- FileWriter writer = null;
- try {
- writer = new FileWriter(saveFile);
+ try (FileWriter writer = new FileWriter(saveFile)) {
for (DynamicCheat cheat : cheatList) {
writer.write(cheat.serialize());
writer.write("\n");
}
- writer.close();
} catch (IOException ex) {
Logger.getLogger(MetaCheat.class.getName()).log(Level.SEVERE, null, ex);
- } finally {
- try {
- writer.close();
- } catch (IOException ex) {
- Logger.getLogger(MetaCheat.class.getName()).log(Level.SEVERE, null, ex);
- }
}
}
public void loadCheats(File saveFile) {
- BufferedReader in = null;
- try {
- in = new BufferedReader(new FileReader(saveFile));
- StringBuilder guts = new StringBuilder();
+ try (BufferedReader in = new BufferedReader(new FileReader(saveFile))) {
String line;
while ((line = in.readLine()) != null) {
DynamicCheat cheat = DynamicCheat.deserialize(line);
addCheat(cheat);
}
- in.close();
} catch (IOException ex) {
Logger.getLogger(MetaCheat.class.getName()).log(Level.SEVERE, null, ex);
- } finally {
- try {
- in.close();
- } catch (IOException ex) {
- Logger.getLogger(MetaCheat.class.getName()).log(Level.SEVERE, null, ex);
- }
}
}
}
diff --git a/src/main/java/jace/cheat/MontezumasRevengeCheats.java b/src/main/java/jace/cheat/MontezumasRevengeCheats.java
index ecd9c32..bfe26e8 100644
--- a/src/main/java/jace/cheat/MontezumasRevengeCheats.java
+++ b/src/main/java/jace/cheat/MontezumasRevengeCheats.java
@@ -3,8 +3,6 @@ package jace.cheat;
import jace.Emulator;
import jace.EmulatorUILogic;
import jace.config.ConfigurableField;
-import jace.core.Computer;
-import jace.core.RAM;
import jace.core.RAMEvent;
import javafx.event.EventHandler;
import javafx.scene.Node;
@@ -54,10 +52,6 @@ public class MontezumasRevengeCheats extends Cheats {
public static int lastX = 0;
- public MontezumasRevengeCheats(Computer computer) {
- super(computer);
- }
-
double mouseX;
double mouseY;
EventHandler listener = (event) -> {
@@ -71,54 +65,55 @@ public class MontezumasRevengeCheats extends Cheats {
@Override
public void registerListeners() {
- RAM memory = Emulator.computer.memory;
if (repulsiveHack) {
- addCheat(RAMEvent.TYPE.WRITE, this::repulsiveBehavior, 0x1508, 0x1518);
+ addCheat("Repulsive", RAMEvent.TYPE.WRITE, this::repulsiveBehavior, 0x1508, 0x1518);
}
if (featherFall) {
- addCheat(RAMEvent.TYPE.WRITE, this::featherFallBehavior, PLAYER_Y);
+ addCheat("Feather fall", RAMEvent.TYPE.WRITE, this::featherFallBehavior, PLAYER_Y);
// Bypass the part that realizes you should die when you hit the floor
- bypassCode(0x6bb3, 0x6bb4);
+ bypassCode("Feather fall code hack", 0x6bb3, 0x6bb4);
}
if (moonJump) {
- addCheat(RAMEvent.TYPE.WRITE, this::moonJumpBehavior, Y_VELOCITY);
+ addCheat("Moon jump", RAMEvent.TYPE.WRITE, this::moonJumpBehavior, Y_VELOCITY);
}
if (infiniteLives) {
- forceValue(11, LIVES);
+ forceValue("Infinite lives", 11, LIVES);
}
if (safePassage) {
- //blank out pattern for floors/doors
- for (int addr = 0x0b54; addr <= 0xb5f; addr++) {
- memory.write(addr, (byte) 0, false, false);
- memory.write(addr + 0x0400, (byte) 0, false, false);
- }
- memory.write(0x0b50, (byte) 0b11010111, false, false);
- memory.write(0x0b51, (byte) 0b00010000, false, false);
- memory.write(0x0b52, (byte) 0b10001000, false, false);
- memory.write(0x0b53, (byte) 0b10101010, false, false);
- memory.write(0x0f50, (byte) 0b10101110, false, false);
- memory.write(0x0f51, (byte) 0b00001000, false, false);
- memory.write(0x0f52, (byte) 0b10000100, false, false);
- memory.write(0x0f53, (byte) 0b11010101, false, false);
- forceValue(32, FLOOR_TIMER);
- forceValue(32, HAZARD_TIMER);
- forceValue(1, HAZARD_FLAG);
+ Emulator.withMemory(memory -> {
+ //blank out pattern for floors/doors
+ for (int addr = 0x0b54; addr <= 0xb5f; addr++) {
+ memory.write(addr, (byte) 0, false, false);
+ memory.write(addr + 0x0400, (byte) 0, false, false);
+ }
+ memory.write(0x0b50, (byte) 0b11010111, false, false);
+ memory.write(0x0b51, (byte) 0b00010000, false, false);
+ memory.write(0x0b52, (byte) 0b10001000, false, false);
+ memory.write(0x0b53, (byte) 0b10101010, false, false);
+ memory.write(0x0f50, (byte) 0b10101110, false, false);
+ memory.write(0x0f51, (byte) 0b00001000, false, false);
+ memory.write(0x0f52, (byte) 0b10000100, false, false);
+ memory.write(0x0f53, (byte) 0b11010101, false, false);
+ forceValue("Hack floor timer", 32, FLOOR_TIMER);
+ forceValue("Hack hazard timer", 32, HAZARD_TIMER);
+ forceValue("Hack hazard flag", 1, HAZARD_FLAG);
+ });
}
if (scoreHack) {
// Score: 900913
- forceValue(0x90, SCORE);
- forceValue(0x09, SCORE + 1);
- forceValue(0x13, SCORE + 2);
+ forceValue("Hack score 1", 0x90, SCORE);
+ forceValue("Hack score 2", 0x09, SCORE + 1);
+ forceValue("Hack score 3", 0x13, SCORE + 2);
}
if (snakeCharmer) {
// Skip the code that determines you're touching an enemy
- bypassCode(0x07963, 0x07964);
+ bypassCode("Snake charmer", 0x07963, 0x07964);
}
if (mouseHack) {
EmulatorUILogic.addMouseListener(listener);
@@ -132,11 +127,11 @@ public class MontezumasRevengeCheats extends Cheats {
}
private void repulsiveBehavior(RAMEvent e) {
- int playerX = computer.getMemory().readRaw(PLAYER_X);
- int playerY = computer.getMemory().readRaw(PLAYER_Y);
+ int playerX = getMemory().readRaw(PLAYER_X);
+ int playerY = getMemory().readRaw(PLAYER_Y);
for (int num = 7; num > 0; num--) {
- int monsterX = computer.getMemory().readRaw(PLAYER_X + num);
- int monsterY = computer.getMemory().readRaw(PLAYER_Y + num);
+ int monsterX = getMemory().readRaw(PLAYER_X + num);
+ int monsterY = getMemory().readRaw(PLAYER_Y + num);
if (monsterX != 0 && monsterY != 0) {
if (Math.abs(monsterY - playerY) < 19) {
if (Math.abs(monsterX - playerX) < 7) {
@@ -149,7 +144,7 @@ public class MontezumasRevengeCheats extends Cheats {
monsterX = 80;
}
}
- computer.getMemory().write(PLAYER_X + num, (byte) monsterX, false, false);
+ getMemory().write(PLAYER_X + num, (byte) monsterX, false, false);
}
}
}
@@ -159,9 +154,9 @@ public class MontezumasRevengeCheats extends Cheats {
private void featherFallBehavior(RAMEvent yCoordChangeEvent) {
if (yCoordChangeEvent.getNewValue() != yCoordChangeEvent.getOldValue()) {
- int yVel = computer.getMemory().readRaw(Y_VELOCITY);
+ int yVel = getMemory().readRaw(Y_VELOCITY);
if (yVel > MAX_VEL) {
- computer.getMemory().write(Y_VELOCITY, (byte) MAX_VEL, false, false);
+ getMemory().write(Y_VELOCITY, (byte) MAX_VEL, false, false);
}
}
}
@@ -177,7 +172,7 @@ public class MontezumasRevengeCheats extends Cheats {
}
private boolean inStartingSequence() {
- int roomLevel = computer.getMemory().readRaw(ROOM_LEVEL);
+ int roomLevel = getMemory().readRaw(ROOM_LEVEL);
return roomLevel == -1;
}
@@ -198,7 +193,7 @@ public class MontezumasRevengeCheats extends Cheats {
private void mouseClicked(MouseButton button) {
byte newX = (byte) (mouseX * X_MAX);
byte newY = (byte) (mouseY * Y_MAX);
- computer.memory.write(PLAYER_X, newX, false, false);
- computer.memory.write(PLAYER_Y, newY, false, false);
+ getMemory().write(PLAYER_X, newX, false, false);
+ getMemory().write(PLAYER_Y, newY, false, false);
}
}
\ No newline at end of file
diff --git a/src/main/java/jace/cheat/PrinceOfPersiaCheats.java b/src/main/java/jace/cheat/PrinceOfPersiaCheats.java
index 77b6545..3ca7374 100644
--- a/src/main/java/jace/cheat/PrinceOfPersiaCheats.java
+++ b/src/main/java/jace/cheat/PrinceOfPersiaCheats.java
@@ -1,28 +1,24 @@
-/*
- * Copyright (C) 2012 Brendan Robert (BLuRry) brendan.robert@gmail.com.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301 USA
- */
+/**
+* Copyright 2024 Brendan Robert
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+**/
+
package jace.cheat;
import jace.EmulatorUILogic;
import jace.apple2e.RAM128k;
-import jace.apple2e.SoftSwitches;
import jace.config.ConfigurableField;
-import jace.core.Computer;
import jace.core.PagedMemory;
import jace.core.RAMEvent;
import javafx.event.EventHandler;
@@ -145,17 +141,13 @@ public class PrinceOfPersiaCheats extends Cheats {
// This is the correct value for an open exit door.
public static int ExitOpen = 172;
- public PrinceOfPersiaCheats(Computer computer) {
- super(computer);
- }
-
double mouseX;
double mouseY;
EventHandler listener = (event) -> {
Node source = (Node) event.getSource();
mouseX = event.getSceneX() / source.getBoundsInLocal().getWidth();
mouseY = event.getSceneY() / source.getBoundsInLocal().getHeight();
- if (event.isPrimaryButtonDown()) {
+ if (event.isPrimaryButtonDown() || event.isSecondaryButtonDown()) {
mouseClicked(event.getButton());
}
};
@@ -173,19 +165,19 @@ public class PrinceOfPersiaCheats extends Cheats {
@Override
public void registerListeners() {
if (velocityHack) {
- addCheat(RAMEvent.TYPE.READ_DATA, true, this::velocityHackBehavior, CharYVel);
+ addCheat("Hack velocity", RAMEvent.TYPE.READ_DATA, true, this::velocityHackBehavior, CharYVel);
}
if (invincibilityHack) {
- forceValue(3, true, KidStrength);
+ forceValue("Hack invincibility", 3, true, KidStrength);
}
if (sleepHack) {
- forceValue(0, true, EnemyAlert);
+ forceValue("Go to sleep!", 0, true, EnemyAlert);
}
if (swordHack) {
- forceValue(1, true, hasSword);
+ forceValue("Can haz sword", 1, true, hasSword);
}
if (timeHack) {
- forceValue(0x69, true, MinLeft);
+ forceValue("Hack time", 0x69, true, MinLeft);
}
if (mouseHack) {
EmulatorUILogic.addMouseListener(listener);
@@ -234,7 +226,7 @@ public class PrinceOfPersiaCheats extends Cheats {
// Note: POP uses a 255-pixel horizontal axis, Pixels 0-57 are offscreen to the left
// and 198-255 offscreen to the right.
// System.out.println("Clicked on " + col + "," + row + " -- screen " + (x * 280) + "," + (y * 192));
- RAM128k mem = (RAM128k) computer.getMemory();
+ RAM128k mem = (RAM128k) getMemory();
PagedMemory auxMem = mem.getAuxMemory();
if (button == MouseButton.PRIMARY) {
@@ -262,7 +254,7 @@ public class PrinceOfPersiaCheats extends Cheats {
byte warpX = (byte) (x * 140 + 58);
// This aliases the Y coordinate so the prince is on the floor at the correct spot.
byte warpY = (byte) ((row * 63) + 54);
-// System.out.println("Warping to " + warpX + "," + warpY);
+ // System.out.println("Warping to " + warpX + "," + warpY);
auxMem.writeByte(KidX, warpX);
auxMem.writeByte(KidY, warpY);
auxMem.writeByte(KidBlockX, (byte) col);
@@ -280,7 +272,7 @@ public class PrinceOfPersiaCheats extends Cheats {
* @param direction
*/
public void performAction(int row, int col, int direction) {
- RAM128k mem = (RAM128k) computer.getMemory();
+ RAM128k mem = (RAM128k) getMemory();
PagedMemory auxMem = mem.getAuxMemory();
byte currentScrn = auxMem.readByte(KidScrn);
if (col < 0) {
@@ -291,7 +283,7 @@ public class PrinceOfPersiaCheats extends Cheats {
}
currentScrn = (byte) scrnLeft;
byte prev = auxMem.readByte(PREV + row);
- byte sprev = auxMem.readByte(SPREV + row);
+ // byte sprev = auxMem.readByte(SPREV + row);
// If the block to the left is gate, let's lie about it being open... for science
// This causes odd-looking screen behavior but it gets the job done.
if (prev == 4) {
diff --git a/src/main/java/jace/cheat/ProgramIdentity.java b/src/main/java/jace/cheat/ProgramIdentity.java
new file mode 100644
index 0000000..9914f0b
--- /dev/null
+++ b/src/main/java/jace/cheat/ProgramIdentity.java
@@ -0,0 +1,119 @@
+package jace.cheat;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.zip.CRC32;
+
+import jace.apple2e.RAM128k;
+import jace.apple2e.SoftSwitches;
+import jace.core.PagedMemory;
+import jace.core.RAMEvent;
+import jace.core.RAMEvent.TYPE;
+
+public class ProgramIdentity extends Cheats {
+ private Map programIdentities;
+
+ @Override
+ public void registerListeners() {
+ addCheat("Track execution", TYPE.ANY, this::trackActivity, 0, 0x0ffff);
+ }
+
+ @Override
+ protected String getDeviceName() {
+ return "Program Identity";
+ }
+
+ int INTERVAL = 1000000;
+ int THRESHOLD_VALUE = 10000;
+ int CLIP_VALUE = THRESHOLD_VALUE * 2;
+ int DECAY = THRESHOLD_VALUE / 2;
+
+ int[] programRegions = new int[512];
+ private void trackActivity(RAMEvent e) {
+ int bank = e.getAddress() >> 8;
+ if (bank >= 0xc0 && bank < 0xd0) {
+ // Skip I/O region
+ return;
+ }
+ // Detect language card ram execution
+ if (bank >= 0xd0 && SoftSwitches.LCRAM.isOff()) {
+ // Skip rom execution
+ return;
+ }
+ if (!e.isMainMemory()) {
+ bank += 256;
+ }
+ if (e.getType() == RAMEvent.TYPE.EXECUTE) {
+ programRegions[bank] = Math.min(CLIP_VALUE, programRegions[bank] + 1);
+ } else if (e.getType() == RAMEvent.TYPE.WRITE) {
+ programRegions[bank] = 0;
+ }
+ }
+
+ private String generateChecksum() {
+ CRC32 crc = new CRC32();
+ RAM128k ram = (RAM128k) getMemory();
+ int bankCount = 0;
+ for (int i=0; i < 512; i++) {
+ if (programRegions[i] > THRESHOLD_VALUE) {
+ PagedMemory mem = ram.getMainMemory();
+ if (i >= 0x0d0 && i < 0x0100) {
+ mem = ram.getLanguageCard();
+ } else if (i >= 0x0100 && i < 0x01d0) {
+ mem = ram.getAuxMemory();
+ } else if (i >= 0x01d0) {
+ mem = ram.getAuxLanguageCard();
+ }
+ bankCount++;
+ crc.update(mem.getMemoryPage((i & 0x0ff) << 8));
+ }
+ }
+ return Long.toHexString(crc.getValue())+"-"+bankCount;
+ }
+
+ @Override
+ public void resume() {
+ super.resume();
+ Arrays.fill(programRegions, 0);
+ readProgramIdentities();
+ }
+
+ int counter = 0;
+ String lastChecksum = "";
+ @Override
+ public void tick() {
+ if (counter++ >= INTERVAL) {
+ String checksum = generateChecksum();
+ if (!checksum.equals(lastChecksum)) {
+ String identity = programIdentities.getOrDefault(checksum, "UNKNOWN");
+ System.out.println(checksum + "," + identity);
+ lastChecksum = checksum;
+ }
+ counter = 0;
+ for (int i=0; i < 512; i++) {
+ programRegions[i] = Math.max(0, programRegions[i] - DECAY);
+ }
+ }
+ }
+
+ private void readProgramIdentities() {
+ // Read from resources file
+ InputStream in = Cheats.class.getResourceAsStream("/jace/cheats/program-identities.txt");
+ try {
+ programIdentities = new HashMap<>();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ String[] parts = line.split(",");
+ programIdentities.put(parts[0], parts[1]);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/java/jace/config/ClassSelection.java b/src/main/java/jace/config/ClassSelection.java
deleted file mode 100644
index ca53310..0000000
--- a/src/main/java/jace/config/ClassSelection.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2012 Brendan Robert (BLuRry) brendan.robert@gmail.com.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301 USA
- */
-package jace.config;
-
-import jace.core.Utility;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-/**
- *
- * @author Brendan Robert (BLuRry) brendan.robert@gmail.com
- */
-
-public class ClassSelection extends DynamicSelection {
-
- Class template = null;
-
- public ClassSelection(Class supertype, Class defaultValue) {
- super(defaultValue);
- template = supertype;
- }
-
- @Override
- public LinkedHashMap getSelections() {
- LinkedHashMap selections = new LinkedHashMap<>();
- Set extends Class> allClasses = Utility.findAllSubclasses(template);
- if (!allClasses.contains(null)) {
- allClasses.add(null);
- }
- List> values = new ArrayList<>();
- if (allowNull()) {
- values.add(new Entry() {
-
- @Override
- public Class getKey() {
- return null;
- }
-
- @Override
- public String getValue() {
- return "***Empty***";
- }
-
- @Override
- public String setValue(String v) {
- throw new UnsupportedOperationException("Not supported yet.");
- }
- });
- }
- for (final Class c : allClasses) {
- Entry entry = new Map.Entry() {
-
- @Override
- public Class getKey() {
- return c;
- }
-
- @Override
- public String getValue() {
- if (c == null) {
- return "**Empty**";
- }
- if (c.isAnnotationPresent(Name.class)) {
- return ((Name) c.getAnnotation(Name.class)).value();
- }
- return c.getSimpleName();
- }
-
- @Override
- public String setValue(String value) {
- throw new UnsupportedOperationException("Not supported yet.");
- }
-
- @Override
- public String toString() {
- return getValue();
- }
-
- @Override
- public boolean equals(Object obj) {
- return super.equals(obj) || obj == getKey() || getKey() != null && getKey().equals(obj);
- }
- };
- values.add(entry);
- }
- Collections.sort(values, (Entry extends Class, String> o1, Entry extends Class, String> o2) -> {
- if (o1.getKey() == null) {
- return -1;
- }
- if (o2.getKey() == null) {
- return 1;
- } else {
- return (o1.getValue().compareTo(o2.getValue()));
- }
- });
- values.stream().forEach((entry) -> {
- Class key = entry.getKey();
- selections.put(key, entry.getValue());
- });
- return selections;
- }
-
- @Override
- public boolean allowNull() {
- return false;
- }
-
- @Override
- public void setValue(Class value) {
- Object v = value;
- if (v != null && v instanceof String) {
- super.setValueByMatch((String) v);
- return;
- }
- super.setValue(value);
- }
-}
\ No newline at end of file
diff --git a/src/main/java/jace/config/ConfigurableField.java b/src/main/java/jace/config/ConfigurableField.java
index 608f4b0..1f80582 100644
--- a/src/main/java/jace/config/ConfigurableField.java
+++ b/src/main/java/jace/config/ConfigurableField.java
@@ -1,21 +1,19 @@
-/*
- * Copyright (C) 2012 Brendan Robert (BLuRry) brendan.robert@gmail.com.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301 USA
- */
+/**
+* Copyright 2024 Brendan Robert
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+**/
+
package jace.config;
import java.lang.annotation.ElementType;
@@ -39,10 +37,10 @@ import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ConfigurableField {
- public String name();
- public String shortName() default "";
- public String defaultValue() default "";
- public String description() default "";
- public String category() default "General";
- public boolean enablesDevice() default false;
+ String name();
+ String shortName() default "";
+ String defaultValue() default "";
+ String description() default "";
+ String category() default "General";
+ boolean enablesDevice() default false;
}
\ No newline at end of file
diff --git a/src/main/java/jace/config/Configuration.java b/src/main/java/jace/config/Configuration.java
index 1527e26..aa0fcb9 100644
--- a/src/main/java/jace/config/Configuration.java
+++ b/src/main/java/jace/config/Configuration.java
@@ -1,40 +1,33 @@
-/*
- * Copyright (C) 2012 Brendan Robert (BLuRry) brendan.robert@gmail.com.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301 USA
- */
+/**
+* Copyright 2024 Brendan Robert
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+**/
+
package jace.config;
-import jace.Emulator;
-import jace.EmulatorUILogic;
-import jace.core.Computer;
-import jace.core.Keyboard;
-import jace.core.Utility;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InvalidClassException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
-import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
@@ -47,9 +40,16 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;
+
+import jace.Emulator;
+import jace.EmulatorUILogic;
+import jace.core.Keyboard;
+import jace.core.Utility;
+import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.TreeItem;
import javafx.scene.image.ImageView;
@@ -60,14 +60,10 @@ import javafx.scene.image.ImageView;
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
*/
public class Configuration implements Reconfigurable {
+ public EmulatorUILogic ui;
- private static Method findAnyMethodByName(Class extends Reconfigurable> aClass, String m) {
- for (Method method : aClass.getMethods()) {
- if (method.getName().equals(m)) {
- return method;
- }
- }
- return null;
+ public Configuration() {
+ ui = Emulator.getUILogic();
}
static ConfigurableField getConfigurableFieldInfo(Reconfigurable subject, String settingName) {
@@ -85,15 +81,6 @@ public class Configuration implements Reconfigurable {
return (f != null && !f.shortName().equals("")) ? f.shortName() : longName;
}
- public static InvokableAction getInvokableActionInfo(Reconfigurable subject, String actionName) {
- for (Method m : subject.getClass().getMethods()) {
- if (m.getName().equals(actionName) && m.isAnnotationPresent(InvokableAction.class)) {
- return m.getAnnotation(InvokableAction.class);
- }
- }
- return null;
- }
-
public static Optional getChangedIcon() {
return Utility.loadIcon("icon_exclaim.gif").map(ImageView::new);
}
@@ -120,6 +107,7 @@ public class Configuration implements Reconfigurable {
* configuration 2) Provide a simple persistence mechanism to load/store
* configuration
*/
+ @SuppressWarnings("all")
public static class ConfigNode extends TreeItem implements Serializable {
public transient ConfigNode root;
@@ -144,14 +132,21 @@ public class Configuration implements Reconfigurable {
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException {
- children = super.getChildren();
+ // Create children list if it doesn't exist
+ if (children == null) {
+ children = FXCollections.observableArrayList();
+ children.setAll(getChildren());
+ }
+ children.setAll(super.getChildren());
id = (String) in.readObject();
name = (String) in.readObject();
- settings = (Map) in.readObject();
- hotkeys = (Map) in.readObject();
+ settings = (Map) in.readObject();
+ hotkeys = (Map) in.readObject();
Object[] nodeArray = (Object[]) in.readObject();
- for (Object child : nodeArray) {
- children.add((ConfigNode) child);
+ synchronized (children) {
+ for (Object child : nodeArray) {
+ children.add((ConfigNode) child);
+ }
}
}
@@ -189,17 +184,16 @@ public class Configuration implements Reconfigurable {
}
public void setFieldValue(String field, Serializable value) {
+ setChanged(true);
if (value != null) {
if (value.equals(getFieldValue(field))) {
return;
}
} else {
if (getFieldValue(field) == null) {
- setChanged(false);
return;
}
}
- setChanged(true);
setRawFieldValue(field, value);
}
@@ -216,19 +210,23 @@ public class Configuration implements Reconfigurable {
}
@Override
- public ObservableList getChildren() {
+ final public ObservableList getChildren() {
return super.getChildren();
}
private boolean removeChild(String childName) {
ConfigNode child = findChild(childName);
- return children.remove(child);
+ synchronized (children) {
+ return children.remove(child);
+ }
}
private ConfigNode findChild(String id) {
- for (ConfigNode node : children) {
- if (id.equalsIgnoreCase(node.id)) {
- return node;
+ synchronized (children) {
+ for (ConfigNode node : children) {
+ if (id.equalsIgnoreCase(node.id)) {
+ return node;
+ }
}
}
return null;
@@ -245,7 +243,9 @@ public class Configuration implements Reconfigurable {
index++;
}
}
- children.add(index, newChild);
+ synchronized (children) {
+ children.add(index, newChild);
+ }
}
private void setChanged(boolean b) {
@@ -258,40 +258,47 @@ public class Configuration implements Reconfigurable {
}
public Stream getTreeAsStream() {
- return Stream.concat(
- Stream.of(this),
- children.stream().flatMap(ConfigNode::getTreeAsStream));
+ synchronized (children) {
+ return Stream.concat(
+ Stream.of(this),
+ children.stream().flatMap(ConfigNode::getTreeAsStream));
+ }
}
}
public static ConfigNode BASE;
- public static EmulatorUILogic ui = Emulator.logic;
- public static Computer emulator = Emulator.computer;
@ConfigurableField(name = "Autosave Changes", description = "If unchecked, changes are only saved when the Save button is pressed.")
public static boolean saveAutomatically = false;
public static void buildTree() {
BASE = new ConfigNode(new Configuration());
- buildTree(BASE, new LinkedHashSet());
+ Set visited = new LinkedHashSet<>();
+ buildTree(BASE, visited);
+ Emulator.withComputer(c->{
+ ConfigNode computer = new ConfigNode(BASE, c);
+ BASE.putChild(c.getName(), computer);
+ buildTree(computer, visited);
+ });
}
+ @SuppressWarnings("all")
private static void buildTree(ConfigNode node, Set visited) {
if (node.subject == null) {
return;
}
- for (Method m : node.subject.getClass().getMethods()) {
- if (!m.isAnnotationPresent(InvokableAction.class)) {
- continue;
- }
- InvokableAction action = m.getDeclaredAnnotation(InvokableAction.class);
- node.hotkeys.put(m.getName(), action.defaultKeyMapping());
- }
+ InvokableActionRegistry registry = InvokableActionRegistry.getInstance();
+ registry.getStaticMethodNames(node.subject.getClass()).stream().forEach((name) ->
+ node.hotkeys.put(name, registry.getStaticMethodInfo(name).defaultKeyMapping())
+ );
+ registry.getInstanceMethodNames(node.subject.getClass()).stream().forEach((name) ->
+ node.hotkeys.put(name, registry.getInstanceMethodInfo(name).defaultKeyMapping())
+ );
for (Field f : node.subject.getClass().getFields()) {
// System.out.println("Evaluating field " + f.getName());
try {
Object o = f.get(node.subject);
- if (!f.getType().isPrimitive() && f.getType() != String.class && visited.contains(o)) {
+ if (o == null || !f.getType().isPrimitive() && f.getType() != String.class && visited.contains(o)) {
continue;
}
visited.add(o);
@@ -301,7 +308,7 @@ public class Configuration implements Reconfigurable {
// if (o.getClass().isAssignableFrom(Reconfigurable.class)) {
// if (Reconfigurable.class.isAssignableFrom(o.getClass())) {
if (f.isAnnotationPresent(ConfigurableField.class)) {
- if (o != null && ISelection.class.isAssignableFrom(o.getClass())) {
+ if (ISelection.class.isAssignableFrom(o.getClass())) {
ISelection selection = (ISelection) o;
node.setRawFieldValue(f.getName(), (Serializable) selection.getSelections().get(selection.getValue()));
} else {
@@ -309,16 +316,14 @@ public class Configuration implements Reconfigurable {
}
continue;
}
- if (o == null) {
- continue;
- }
- if (o instanceof Reconfigurable) {
- Reconfigurable r = (Reconfigurable) o;
+ if (o instanceof Reconfigurable r) {
ConfigNode child = node.findChild(r.getName());
if (child == null || !child.subject.equals(o)) {
child = new ConfigNode(node, r);
node.putChild(f.getName(), child);
+ } else {
+ Logger.getLogger(Configuration.class.getName()).severe("Unable to find child named %s for node %s".formatted(r.getName(), node.name));
}
buildTree(child, visited);
} else if (o.getClass().isArray()) {
@@ -331,8 +336,7 @@ public class Configuration implements Reconfigurable {
if (Optional.class.isAssignableFrom(type)) {
Type genericTypes = f.getGenericType();
// System.out.println("Looking at generic parmeters " + genericTypes.getTypeName() + " for reconfigurable class, type " + genericTypes.getClass().getName());
- if (genericTypes instanceof GenericArrayType) {
- GenericArrayType aType = (GenericArrayType) genericTypes;
+ if (genericTypes instanceof GenericArrayType aType) {
ParameterizedType pType = (ParameterizedType) aType.getGenericComponentType();
if (pType.getActualTypeArguments().length != 1) {
continue;
@@ -346,11 +350,13 @@ public class Configuration implements Reconfigurable {
continue;
}
- for (Optional child : (Optional[]) o) {
- if (child.isPresent()) {
- children.add(child.get());
- } else {
- children.add(null);
+ synchronized (children) {
+ for (Optional child : (Optional[]) o) {
+ if (child.isPresent()) {
+ children.add(child.get());
+ } else {
+ children.add(null);
+ }
}
}
}
@@ -386,7 +392,6 @@ public class Configuration implements Reconfigurable {
defaultKeyMapping = "meta+ctrl+s"
)
public static void saveSettings() {
- FileOutputStream fos = null;
{
ObjectOutputStream oos = null;
try {
@@ -417,29 +422,29 @@ public class Configuration implements Reconfigurable {
defaultKeyMapping = "meta+ctrl+r"
)
public static void loadSettings() {
- {
- boolean successful = false;
- ObjectInputStream ois = null;
+ boolean successful = false;
+ ObjectInputStream ois = null;
+ try {
+ ois = new ObjectInputStream(new FileInputStream(getSettingsFile()));
+ ConfigNode newRoot = (ConfigNode) ois.readObject();
+ applyConfigTree(newRoot, BASE);
+ successful = true;
+ } catch (FileNotFoundException ex) {
+ // This just means there are no settings to be saved -- just ignore it.
+ } catch (InvalidClassException | NullPointerException ex) {
+ Logger.getLogger(Configuration.class.getName()).log(Level.WARNING, "Unable to load settings, Jace version is newer and incompatible with old settings.");
+ } catch (ClassNotFoundException | IOException ex) {
+ Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex);
+ } finally {
try {
- ois = new ObjectInputStream(new FileInputStream(getSettingsFile()));
- ConfigNode newRoot = (ConfigNode) ois.readObject();
- applyConfigTree(newRoot, BASE);
- successful = true;
- } catch (FileNotFoundException ex) {
- // This just means there are no settings to be saved -- just ignore it.
- } catch (ClassNotFoundException | IOException ex) {
- Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex);
- } finally {
- try {
- if (ois != null) {
- ois.close();
- }
- if (!successful) {
- applySettings(BASE);
- }
- } catch (IOException ex) {
- Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex);
+ if (ois != null) {
+ ois.close();
}
+ if (!successful) {
+ applySettings(BASE);
+ }
+ } catch (IOException ex) {
+ Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
@@ -452,6 +457,34 @@ public class Configuration implements Reconfigurable {
return new File(System.getProperty("user.dir"), ".jace.conf");
}
+ public static void registerKeyHandlers() {
+ registerKeyHandlers(BASE, true);
+ }
+
+ public static void registerKeyHandlers(ConfigNode node, boolean recursive) {
+ Keyboard.unregisterAllHandlers(node.subject);
+ InvokableActionRegistry registry = InvokableActionRegistry.getInstance();
+ node.hotkeys.keySet().stream().forEach((name) -> {
+ InvokableAction action = registry.getStaticMethodInfo(name);
+ if (action != null) {
+ for (String code : node.hotkeys.get(name)) {
+ Keyboard.registerInvokableAction(action, node.subject, registry.getStaticFunction(name), code);
+ }
+ }
+ action = registry.getInstanceMethodInfo(name);
+ if (action != null) {
+ for (String code : node.hotkeys.get(name)) {
+ Keyboard.registerInvokableAction(action, node.subject, registry.getInstanceFunction(name), code);
+ }
+ }
+ });
+ if (recursive) {
+ node.getChildren().stream().forEach((child) -> {
+ registerKeyHandlers(child, true);
+ });
+ }
+ }
+
/**
* Apply settings from node tree to the object model This also calls
* "reconfigure" on objects in sequence
@@ -461,33 +494,29 @@ public class Configuration implements Reconfigurable {
* descendants
*/
public static boolean applySettings(ConfigNode node) {
- boolean resume = false;
- if (node == BASE) {
- resume = Emulator.computer.pause();
- }
- boolean hasChanged = false;
- if (node.changed) {
- doApply(node);
- hasChanged = true;
- }
+ AtomicBoolean hasChanged = new AtomicBoolean(false);
- // Now that the object structure reflects the current configuration,
- // process reconfiguration from the children, etc.
- for (ConfigNode child : node.getChildren()) {
- hasChanged |= applySettings(child);
- }
+ Emulator.whileSuspended(c-> {
+ if (node.changed) {
+ doApply(node);
+ hasChanged.set(true);
+ }
- if (node.equals(BASE) && hasChanged) {
+ // Now that the object structure reflects the current configuration,
+ // process reconfiguration from the children, etc.
+ for (ConfigNode child : node.getChildren()) {
+ if (applySettings(child)) hasChanged.set(true);
+ }
+ });
+
+ if (node.equals(BASE) && hasChanged.get()) {
buildTree();
}
- if (resume) {
- Emulator.computer.resume();
- }
-
- return hasChanged;
+ return hasChanged.get();
}
+ @SuppressWarnings("all")
private static void applyConfigTree(ConfigNode newRoot, ConfigNode oldRoot) {
if (oldRoot == null || newRoot == null) {
return;
@@ -509,18 +538,10 @@ public class Configuration implements Reconfigurable {
});
}
+ @SuppressWarnings("all")
private static void doApply(ConfigNode node) {
List removeList = new ArrayList<>();
- Keyboard.unregisterAllHandlers(node.subject);
- node.hotkeys.keySet().stream().forEach((m) -> {
- Method method = findAnyMethodByName(node.subject.getClass(), m);
- if (method != null) {
- InvokableAction action = method.getAnnotation(InvokableAction.class);
- for (String code : node.hotkeys.get(m)) {
- Keyboard.registerInvokableAction(action, node.subject, method, code);
- }
- }
- });
+ registerKeyHandlers(node, false);
for (String f : node.settings.keySet()) {
try {
@@ -585,7 +606,7 @@ public class Configuration implements Reconfigurable {
String fieldName = parts[1];
ConfigNode n = shortNames.get(deviceName.toLowerCase());
if (n == null) {
- System.err.println("Unable to find device named " + deviceName + ", try one of these: " + Utility.join(shortNames.keySet(), ", "));
+ System.err.println("Unable to find device named " + deviceName + ", try one of these: " + String.join(", ", shortNames.keySet()));
continue;
}
@@ -607,7 +628,7 @@ public class Configuration implements Reconfigurable {
}
}
if (!found) {
- System.err.println("Unable to find property " + fieldName + " for device " + deviceName + ". Try one of these: " + Utility.join(shortFieldNames, ", "));
+ System.err.println("Unable to find property " + fieldName + " for device " + deviceName + ". Try one of these: " + String.join(", ", shortFieldNames));
}
}
}
@@ -615,27 +636,29 @@ public class Configuration implements Reconfigurable {
private static void buildNodeMap(ConfigNode n, Map shortNames) {
// System.out.println("Encountered " + n.subject.getShortName().toLowerCase());
shortNames.put(n.subject.getShortName().toLowerCase(), n);
- n.getChildren().stream().forEach((c) -> {
- buildNodeMap(c, shortNames);
- });
+ synchronized (n.getChildren()) {
+ n.getChildren().stream().forEach((c) -> {
+ buildNodeMap(c, shortNames);
+ });
+ }
}
- private static void printTree(ConfigNode n, String prefix, int i) {
- n.getAllSettingNames().stream().forEach((setting) -> {
- for (int j = 0; j < i; j++) {
- System.out.print(" ");
- }
- ConfigurableField f = null;
- try {
- f = n.subject.getClass().getField(setting).getAnnotation(ConfigurableField.class);
- } catch (NoSuchFieldException | SecurityException ex) {
- Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex);
- }
- String sn = (f != null && !f.shortName().equals("")) ? f.shortName() : setting;
- System.out.println(prefix + ">>" + setting + " (" + n.subject.getShortName() + "." + sn + ")");
- });
- n.getChildren().stream().forEach((c) -> {
- printTree(c, prefix + "." + c.toString(), i + 1);
- });
- }
+ // private static void printTree(ConfigNode n, String prefix, int i) {
+ // n.getAllSettingNames().stream().forEach((setting) -> {
+ // for (int j = 0; j < i; j++) {
+ // System.out.print(" ");
+ // }
+ // ConfigurableField f = null;
+ // try {
+ // f = n.subject.getClass().getField(setting).getAnnotation(ConfigurableField.class);
+ // } catch (NoSuchFieldException | SecurityException ex) {
+ // Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex);
+ // }
+ // String sn = (f != null && !f.shortName().equals("")) ? f.shortName() : setting;
+ // System.out.println(prefix + ">>" + setting + " (" + n.subject.getShortName() + "." + sn + ")");
+ // });
+ // n.getChildren().stream().forEach((c) -> {
+ // printTree(c, prefix + "." + c, i + 1);
+ // });
+ // }
}
diff --git a/src/main/java/jace/config/ConfigurationUIController.java b/src/main/java/jace/config/ConfigurationUIController.java
index edd4a26..0f111e9 100644
--- a/src/main/java/jace/config/ConfigurationUIController.java
+++ b/src/main/java/jace/config/ConfigurationUIController.java
@@ -1,19 +1,19 @@
package jace.config;
-import jace.config.Configuration.ConfigNode;
import java.io.File;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashSet;
+import java.util.Optional;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
-import java.util.stream.Collectors;
+
+import jace.config.Configuration.ConfigNode;
import javafx.beans.Observable;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
@@ -88,11 +88,12 @@ public class ConfigurationUIController {
assert settingsScroll != null : "fx:id=\"settingsScroll\" was not injected: check your FXML file 'Configuration.fxml'.";
assert deviceTree != null : "fx:id=\"deviceTree\" was not injected: check your FXML file 'Configuration.fxml'.";
assert treeScroll != null : "fx:id=\"treeScroll\" was not injected: check your FXML file 'Configuration.fxml'.";
- resetDeviceTree();
+ cancelConfig(null);
deviceTree.getSelectionModel().selectedItemProperty().addListener(this::selectionChanged);
deviceTree.maxWidthProperty().bind(treeScroll.widthProperty());
}
+ @SuppressWarnings("all")
private void resetDeviceTree() {
Set expanded = new HashSet<>();
String current = getCurrentNodePath();
@@ -104,8 +105,8 @@ public class ConfigurationUIController {
private void getExpandedNodes(String prefix, TreeItem root, Set expanded) {
if (root == null) return;
- root.getChildren().stream().filter((item) -> (item.isExpanded())).forEach((item) -> {
- String name = prefix+item.toString();
+ root.getChildren().stream().filter(TreeItem::isExpanded).forEach((item) -> {
+ String name = prefix+ item;
expanded.add(name);
getExpandedNodes(name+DELIMITER, item, expanded);
});
@@ -113,7 +114,7 @@ public class ConfigurationUIController {
private void setExpandedNodes(String prefix, TreeItem root, Set expanded) {
if (root == null) return;
- root.getChildren().stream().forEach((item) -> {
+ root.getChildren().forEach((item) -> {
String name = prefix+item.toString();
if (expanded.contains(name)) {
item.setExpanded(true);
@@ -133,6 +134,7 @@ public class ConfigurationUIController {
return out;
}
+ @SuppressWarnings("all")
private void setCurrentNodePath(String value) {
if (value == null) return;
String[] parts = value.split(Pattern.quote(DELIMITER));
@@ -163,12 +165,8 @@ public class ConfigurationUIController {
if (node == null) {
return;
}
- node.hotkeys.forEach((name, values) -> {
- settingsVbox.getChildren().add(buildKeyShortcutRow(node, name, values));
- });
- node.settings.forEach((name, value) -> {
- settingsVbox.getChildren().add(buildSettingRow(node, name, value));
- });
+ node.hotkeys.forEach((name, values) -> buildKeyShortcutRow(node, name, values).ifPresent(settingsVbox.getChildren()::add));
+ node.settings.forEach((name, value) -> settingsVbox.getChildren().add(buildSettingRow(node, name, value)));
}
private Node buildSettingRow(ConfigNode node, String settingName, Serializable value) {
@@ -188,33 +186,36 @@ public class ConfigurationUIController {
return row;
}
- private Node buildKeyShortcutRow(ConfigNode node, String actionName, String[] values) {
- InvokableAction actionInfo = Configuration.getInvokableActionInfo(node.subject, actionName);
+ private Optional buildKeyShortcutRow(ConfigNode node, String actionName, String[] values) {
+ InvokableActionRegistry registry = InvokableActionRegistry.getInstance();
+ InvokableAction actionInfo = registry.getInstanceMethodInfo(actionName);
if (actionInfo == null) {
- return null;
+ actionInfo = registry.getStaticMethodInfo(actionName);
+ }
+ if (actionInfo == null) {
+ return Optional.empty();
}
HBox row = new HBox();
row.getStyleClass().add("setting-row");
Label label = new Label(actionInfo.name());
label.getStyleClass().add("setting-keyboard-shortcut");
label.setMinWidth(150.0);
- String value = Arrays.stream(values).collect(Collectors.joining(" or "));
+ String value = String.join(" or ", values);
Text widget = new Text(value);
widget.setWrappingWidth(180.0);
widget.getStyleClass().add("setting-keyboard-value");
- widget.setOnMouseClicked((event) -> {
- editKeyboardShortcut(node, actionName, widget);
- });
+ widget.setOnMouseClicked((event) -> editKeyboardShortcut(node, actionName, widget));
label.setLabelFor(widget);
row.getChildren().add(label);
row.getChildren().add(widget);
- return row;
+ return Optional.of(row);
}
private void editKeyboardShortcut(ConfigNode node, String actionName, Text widget) {
throw new UnsupportedOperationException("Not supported yet.");
}
+ @SuppressWarnings("all")
private Node buildEditField(ConfigNode node, String settingName, Serializable value) {
Field field;
try {
@@ -237,8 +238,6 @@ public class ConfigurationUIController {
}
} else if (type.equals(File.class)) {
// TODO: Add file support!
- } else if (Class.class.isEnum()) {
- // TODO: Add enumeration support!
} else if (ISelection.class.isAssignableFrom(type)) {
return buildDynamicSelectComponent(node, settingName, value);
}
@@ -247,21 +246,18 @@ public class ConfigurationUIController {
private Node buildTextField(ConfigNode node, String settingName, Serializable value, String validationPattern) {
TextField widget = new TextField(String.valueOf(value));
- widget.textProperty().addListener((e) -> {
- node.setFieldValue(settingName, widget.getText());
- });
+ widget.textProperty().addListener((e) -> node.setFieldValue(settingName, widget.getText()));
return widget;
}
private Node buildBooleanField(ConfigNode node, String settingName, Serializable value) {
CheckBox widget = new CheckBox();
widget.setSelected(value.equals(Boolean.TRUE));
- widget.selectedProperty().addListener((e) -> {
- node.setFieldValue(settingName, widget.isSelected());
- });
+ widget.selectedProperty().addListener((e) -> node.setFieldValue(settingName, widget.isSelected()));
return widget;
}
+ @SuppressWarnings("all")
private Node buildDynamicSelectComponent(ConfigNode node, String settingName, Serializable value) {
try {
DynamicSelection sel = (DynamicSelection) node.subject.getClass().getField(settingName).get(node.subject);
@@ -284,9 +280,9 @@ public class ConfigurationUIController {
} else {
widget.setValue(selected);
}
- widget.valueProperty().addListener((Observable e) -> {
- node.setFieldValue(settingName, widget.getConverter().toString(widget.getValue()));
- });
+ widget.valueProperty().addListener((Observable e) ->
+ node.setFieldValue(settingName, widget.getConverter().toString(widget.getValue()))
+ );
return widget;
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex) {
Logger.getLogger(ConfigurationUIController.class.getName()).log(Level.SEVERE, null, ex);
diff --git a/src/main/java/jace/config/DeviceEnum.java b/src/main/java/jace/config/DeviceEnum.java
new file mode 100644
index 0000000..78f8ea1
--- /dev/null
+++ b/src/main/java/jace/config/DeviceEnum.java
@@ -0,0 +1,7 @@
+package jace.config;
+
+public interface DeviceEnum {
+ public String getName();
+ public T create();
+ public boolean isInstance(T t);
+}
\ No newline at end of file
diff --git a/src/main/java/jace/config/DeviceSelection.java b/src/main/java/jace/config/DeviceSelection.java
new file mode 100644
index 0000000..44116b4
--- /dev/null
+++ b/src/main/java/jace/config/DeviceSelection.java
@@ -0,0 +1,80 @@
+/**
+* Copyright 2024 Brendan Robert
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+**/
+
+package jace.config;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+/**
+ *
+ * @author Brendan Robert (BLuRry) brendan.robert@gmail.com
+ * @param Enum class which implements DeviceEnum
+ */
+// C is an enum class which implements DeviceEnum
+@SuppressWarnings("all")
+public class DeviceSelection extends DynamicSelection {
+
+ Class enumClass;
+ boolean nullAllowed = false;
+
+ public DeviceSelection(Class enumClass, C defaultValue) {
+ super(defaultValue);
+ if (defaultValue == null) {
+ nullAllowed = true;
+ }
+ this.enumClass = enumClass;
+ }
+
+ public DeviceSelection(Class enumClass, C defaultValue, boolean nullAllowed) {
+ this(enumClass, defaultValue);
+ this.nullAllowed = nullAllowed;
+ }
+
+ @Override
+ public LinkedHashMap getSelections() {
+ LinkedHashMap selections = new LinkedHashMap<>();
+ if (allowNull()) {
+ selections.put(null, "***Empty***");
+ }
+ // Sort enum constants by getName
+ List sorted = new ArrayList<>();
+ sorted.addAll(Arrays.asList(enumClass.getEnumConstants()));
+ Collections.sort(sorted, (C o1, C o2) -> o1.getName().compareTo(o2.getName()));
+ for (C c : enumClass.getEnumConstants()) {
+ selections.put(c, c.getName());
+ }
+ return selections;
+ }
+
+ @Override
+ public boolean allowNull() {
+ return nullAllowed;
+ }
+
+ @Override
+ public void setValue(C value) {
+ Object v = value;
+ if (v != null && v instanceof String) {
+ super.setValueByMatch((String) v);
+ return;
+ }
+ super.setValue(value);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/jace/config/DynamicSelection.java b/src/main/java/jace/config/DynamicSelection.java
index d8d9bd3..79889a5 100644
--- a/src/main/java/jace/config/DynamicSelection.java
+++ b/src/main/java/jace/config/DynamicSelection.java
@@ -1,27 +1,26 @@
-/*
- * Copyright (C) 2012 Brendan Robert (BLuRry) brendan.robert@gmail.com.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301 USA
- */
+/**
+* Copyright 2024 Brendan Robert
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+**/
+
package jace.config;
-import jace.core.Utility;
import java.util.Iterator;
import java.util.Map;
+import jace.core.Utility;
+
/**
*
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
diff --git a/src/main/java/jace/config/ISelection.java b/src/main/java/jace/config/ISelection.java
index 4c66b48..2672144 100644
--- a/src/main/java/jace/config/ISelection.java
+++ b/src/main/java/jace/config/ISelection.java
@@ -1,21 +1,19 @@
-/*
- * Copyright (C) 2012 Brendan Robert (BLuRry) brendan.robert@gmail.com.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301 USA
- */
+/**
+* Copyright 2024 Brendan Robert
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+**/
+
package jace.config;
import java.io.Serializable;
@@ -27,11 +25,11 @@ import java.util.LinkedHashMap;
*/
public interface ISelection extends Serializable {
- public LinkedHashMap extends T, String> getSelections();
+ LinkedHashMap extends T, String> getSelections();
- public T getValue();
+ T getValue();
- public void setValue(T value);
+ void setValue(T value);
- public void setValueByMatch(String value);
+ void setValueByMatch(String value);
}
diff --git a/src/main/java/jace/config/InvokableAction.java b/src/main/java/jace/config/InvokableAction.java
index 9f96782..4bbde77 100644
--- a/src/main/java/jace/config/InvokableAction.java
+++ b/src/main/java/jace/config/InvokableAction.java
@@ -1,21 +1,19 @@
-/*
- * Copyright (C) 2012 Brendan Robert (BLuRry) brendan.robert@gmail.com.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301 USA
- */
+/**
+* Copyright 2024 Brendan Robert
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+**/
+
package jace.config;
import java.lang.annotation.ElementType;
@@ -26,19 +24,19 @@ import java.lang.annotation.Target;
/**
* A invokable action annotation means that an object method can be called by the end-user.
* This serves as a hook for keybindings as well as semantic navigation potential.
- *
+ *
* Name should be short, meaningful, and succinct. e.g. "Insert disk"
- *
+ *
* Category can be used to group actions by overall topic, for example an automated table of contents
- *
+ *
* Description is descriptive text which provides additional clarity, e.g.
* "This will present you with a file selection dialog to pick a floppy disk image.
* Currently, dos-ordered (DSK, DO), Prodos-ordered (PO), and Nibble (NIB) formats are supported.
- *
+ *
* Alternatives should be delimited by semicolons) can provide more powerful search
* For "insert disk", alternatives might be "change disk;switch disk" and
* reboot might have alternatives as "warm start;cold start;boot;restart".
- *
+ *
* NOTE: Any method that implements this must be public and take no parameters!
* If a method signature is not correct, it will result in a runtime exception
* when the action is triggered. There is no way to offer a compiler
@@ -51,37 +49,37 @@ public @interface InvokableAction {
/*
* Should be short and meaningful name for action being invoked, e.g. "Insert disk"
*/
- public String name();
+ String name();
/*
* Can be used to group actions by overall topic, for example an automated table of contents
* To be determined...
*/
- public String category() default "General";
+ String category() default "General";
/*
* More descriptive text which provides additional clarity, e.g.
* "This will present you with a file selection dialog to pick a floppy disk image.
* Currently, dos-ordered (DSK, DO), Prodos-ordered (PO), and Nibble (NIB) formats are supported."
*/
- public String description() default "";
+ String description() default "";
/*
* Alternatives should be delimited by semicolons) can provide more powerful search
* For "insert disk", alternatives might be "change disk;switch disk" and
* reboot might have alternatives as "warm start;cold start;boot;restart".
*/
- public String alternatives() default "";
+ String alternatives() default "";
/*
* If true, the key event will be consumed and not processed by any other event handlers
* If the corresponding method returns a boolean, that value will be used instead.
* True = consume (stop processing keystroke), false = pass-through to other handlers
*/
- public boolean consumeKeyEvent() default true;
+ boolean consumeKeyEvent() default true;
/*
* If false (default) event is only triggered on press, not release. If true,
* method is notified on press and on release
*/
- public boolean notifyOnRelease() default false;
+ boolean notifyOnRelease() default false;
/*
* Standard keyboard mapping
*/
- public String[] defaultKeyMapping();
+ String[] defaultKeyMapping();
}
\ No newline at end of file
diff --git a/src/main/java/jace/config/InvokableActionAnnotationProcessor.java b/src/main/java/jace/config/InvokableActionAnnotationProcessor.java
new file mode 100644
index 0000000..b8fd74a
--- /dev/null
+++ b/src/main/java/jace/config/InvokableActionAnnotationProcessor.java
@@ -0,0 +1,168 @@
+package jace.config;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.Messager;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.annotation.processing.SupportedSourceVersion;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+
+// Compile-time annotation processor which creates a registry of all static methods annotated with @InvokableAction.
+@SupportedSourceVersion(SourceVersion.RELEASE_17)
+@SupportedAnnotationTypes("jace.config.InvokableAction")
+public class InvokableActionAnnotationProcessor extends AbstractProcessor {
+ Messager messager;
+ Map staticMethods = new HashMap<>();
+ Map instanceMethods = new HashMap<>();
+
+ @Override
+ public synchronized void init(ProcessingEnvironment processingEnv) {
+ super.init(processingEnv);
+ this.messager = processingEnv.getMessager();
+ messager.printMessage(javax.tools.Diagnostic.Kind.NOTE, "InvokableActionAnnotationProcessor init()");
+ }
+
+ @Override
+ public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ messager.printMessage(javax.tools.Diagnostic.Kind.NOTE, "InvokableActionAnnotationProcessor process()");
+
+ // Get list of methods annotated with @InvokableAction.
+ Set extends Element> elements = roundEnv.getElementsAnnotatedWith(InvokableAction.class);
+ for (Element element : elements) {
+ if (element.getModifiers().contains(javax.lang.model.element.Modifier.STATIC)) {
+ // If the annotation method is static, add it to the static method registry.
+ trackStaticMethod(element);
+ } else {
+ // For non-static methods, track in a separate registry.
+ trackInstanceMethod(element);
+ }
+ try {
+ // Write class that contains static and instance methods.
+ writeRegistryClass();
+ } catch (IOException ex) {
+ messager.printMessage(javax.tools.Diagnostic.Kind.ERROR, "Error writing InvokableActionRegistry.java: " + ex.getMessage());
+ }
+ }
+ return true;
+ }
+
+ private void trackStaticMethod(Element element) {
+ // Store the method in the static method registry.
+ staticMethods.put(element.getAnnotation(InvokableAction.class), (ExecutableElement) element);
+ }
+
+ private void trackInstanceMethod(Element element) {
+ // Store the method in the instance method registry.
+ instanceMethods.put(element.getAnnotation(InvokableAction.class), (ExecutableElement) element);
+ }
+
+ private String serializeArrayOfStrings(String... strings) {
+ return Arrays.stream(strings).map(s -> "\"" + s + "\"").collect(Collectors.joining(","));
+ }
+
+ private void serializeInvokableAction(InvokableAction annotation, String variableName, PrintWriter writer) {
+ writer.append("""
+ %s = createInvokableAction("%s", "%s", "%s", "%s", %s, %s, new String[] {%s});
+ """.formatted(
+ variableName,
+ annotation.name(),
+ annotation.category(),
+ annotation.description(),
+ annotation.alternatives(),
+ annotation.consumeKeyEvent(),
+ annotation.notifyOnRelease(),
+ serializeArrayOfStrings(annotation.defaultKeyMapping())
+ ));
+ }
+
+ // Write the registry class.
+ private void writeRegistryClass() throws IOException {
+ Files.createDirectories(new File("target/generated-sources/jace/config").toPath());
+ try (PrintWriter writer = new PrintWriter(new FileWriter("target/generated-sources/jace/config/InvokableActionRegistryImpl.java"))) {
+ writer.write("""
+package jace.config;
+
+import java.util.logging.Level;
+
+public class InvokableActionRegistryImpl extends InvokableActionRegistry {
+ @Override
+ public void init() {
+ InvokableAction annotation;
+""");
+ for (Map.Entry entry : staticMethods.entrySet()) {
+ InvokableAction annotation = entry.getKey();
+ ExecutableElement method = entry.getValue();
+ String packageName = method.getEnclosingElement().getEnclosingElement().toString();
+ String className = method.getEnclosingElement().getSimpleName().toString();
+ String fqnClassName = packageName + "." + className;
+ serializeInvokableAction(annotation, "annotation", writer);
+ boolean takesBoolenParameter = method.getParameters().size() == 1 && method.getParameters().get(0).asType().toString().equalsIgnoreCase("boolean");
+ boolean returnsBoolean = method.getReturnType().toString().equalsIgnoreCase("boolean");
+ writer.write("""
+ putStaticAction(annotation.name(), %s.class, annotation, (b) -> {
+ try {
+ %s %s.%s(%s);
+ } catch (Exception ex) {
+ logger.log(Level.SEVERE, "Error invoking %s", ex);
+ %s
+ }
+ });
+ """.formatted(
+ fqnClassName,
+ returnsBoolean ? "return " : "",
+ fqnClassName,
+ method.getSimpleName(),
+ takesBoolenParameter ? "b" : "",
+ fqnClassName + "." + method.getSimpleName(),
+ returnsBoolean ? "return false;" : ""
+ ));
+ }
+
+ // Now for the instance methods, do the same except use a biconsumer which takes the instance as well as the boolean parameter.
+ for (Map.Entry entry : instanceMethods.entrySet()) {
+ InvokableAction annotation = entry.getKey();
+ ExecutableElement method = entry.getValue();
+ String packageName = method.getEnclosingElement().getEnclosingElement().toString();
+ String className = method.getEnclosingElement().getSimpleName().toString();
+ String fqnClassName = packageName + "." + className;
+ serializeInvokableAction(annotation, "annotation", writer);
+ boolean takesBoolenParameter = method.getParameters().size() == 1 && method.getParameters().get(0).asType().toString().equalsIgnoreCase("boolean");
+ boolean returnsBoolean = method.getReturnType().toString().equalsIgnoreCase("boolean");
+ writer.write("""
+ putInstanceAction(annotation.name(), %s.class, annotation, (o, b) -> {
+ try {
+ %s ((%s) o).%s(%s);
+ } catch (Exception ex) {
+ logger.log(Level.SEVERE, "Error invoking %s", ex);
+ %s
+ }
+ });
+ """.formatted(
+ fqnClassName,
+ returnsBoolean ? "return " : "",
+ fqnClassName,
+ method.getSimpleName(),
+ takesBoolenParameter ? "b" : "",
+ fqnClassName + "." + method.getSimpleName(),
+ returnsBoolean ? "return false;" : ""
+ ));
+ }
+ writer.write("}\n}");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/jace/config/InvokableActionRegistry.java b/src/main/java/jace/config/InvokableActionRegistry.java
new file mode 100644
index 0000000..666077f
--- /dev/null
+++ b/src/main/java/jace/config/InvokableActionRegistry.java
@@ -0,0 +1,149 @@
+package jace.config;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.logging.Logger;
+
+@SuppressWarnings("all")
+public abstract class InvokableActionRegistry {
+ protected static final Logger logger = Logger.getLogger(InvokableActionRegistry.class.getName());
+ private final Map> staticMethodNames = new HashMap<>();
+ private final Map staticMethodInfo = new HashMap<>();
+ private final Map> staticMethodCallers = new HashMap<>();
+ private final Map> instanceMethodNames = new HashMap<>();
+ private final Map instanceMethodInfo = new HashMap<>();
+ private final Map> instanceMethodCallers = new HashMap<>();
+
+ protected static InvokableActionRegistry instance;
+
+ public static InvokableActionRegistry getInstance() {
+ if (instance == null) {
+ instance = new InvokableActionRegistryImpl();
+ instance.init();
+ }
+ return instance;
+ }
+
+
+ abstract public void init();
+
+ final public void putStaticAction(String name, Class c, InvokableAction action, Consumer caller) {
+ putStaticAction(name, c, action, (b) -> {
+ caller.accept(b);
+ return true;
+ });
+ }
+
+ final public void putStaticAction(String name, Class c, InvokableAction action, Function caller) {
+ staticMethodInfo.put(name, action);
+ staticMethodCallers.put(name, caller);
+ staticMethodNames.computeIfAbsent(c, k -> new TreeSet<>()).add(name);
+ }
+
+ public void putInstanceAction(String name, Class c, InvokableAction action, BiConsumer